{"_id":"tyx","_rev":"162-7f5634caec3a0193984e62a9f4e52c4b","name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","dist-tags":{"latest":"0.2.5","beta":"0.3.66"},"versions":{"0.0.0":{"version":"0.0.0","description":"This package name is reserved.","name":"tyx","_id":"tyx@0.0.0","scripts":{},"_shasum":"6ff2d5756cbddf3d184e81ba483b310d67d376bb","_from":".","_npmVersion":"3.10.10","_nodeVersion":"6.10.3","_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"maintainers":[{"name":"kbajalc","email":"kbajalc@gmail.com"}],"dist":{"shasum":"6ff2d5756cbddf3d184e81ba483b310d67d376bb","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.0.0.tgz","integrity":"sha512-7Ik0OLDP90gl/tmiW159RYwE+Bu6oJuLyHH4eHBBxlGX68pCLGROJ2QpWeKiaoXpNqEV4tTUOH2W42MOc369pA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCeq+PcAaIeWmZbwbym0JtXIAezcEPuzp6fmAWzbGnkcwIhANHfKM3RBaBMzrdzYODgiJtz+WnVIgFCgkYQBSWwXMXs"}]},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx-0.0.0.tgz_1500295178977_0.5512047838419676"},"directories":{}},"0.1.0":{"name":"tyx","description":"TyX Core Framework, Serverless back-end framework in TypeScript for AWS Lambda","version":"0.1.0","private":false,"license":"MIT","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"dependencies":{"aws-serverless-express":"^3.0.2","body-parser":"^1.17.2","express":"^4.15.3","jsonwebtoken":"^7.4.1","reflect-metadata":"^0.1.10","uuid":"^3.0.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.16.3","@types/express":"^4.0.35","@types/jsonwebtoken":"^7.2.0","@types/node":"^7.0.33","@types/uuid":"^2.0.30","aws-sdk":"^2.67.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.3","gulp-sourcemaps":"^2.6.1","gulp-typescript":"^3.2.2","gulpclass":"^0.1.2","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","ts-node":"^3.3.0","typescript":"^2.5.2"},"homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.0","scripts":{},"_shasum":"e4c763c7e26c2db881ccdd876ded38379f5f242d","_from":".","_npmVersion":"3.10.10","_nodeVersion":"6.10.3","_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"dist":{"shasum":"e4c763c7e26c2db881ccdd876ded38379f5f242d","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.0.tgz","integrity":"sha512-o7pxnvJLzsegDeDnCa0CnAHR+IpiEvrzOz0GcxBUP9U2/dtGwlTnWDOryXmLCuA0tbdWcM+OSn8CY5iLbJryTQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICn+KDn7ww+9VMnskTmSkT1lNorz/Crf7cuarhv5HJAXAiEAlSt5sYOjGGEEr4HyMh5kPDpKnC0p3znKj/SOa8nST2U="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx-0.1.0.tgz_1509529779870_0.5779919878114015"},"directories":{}},"0.1.1":{"name":"tyx","description":"TyX Core Framework, Serverless back-end framework in TypeScript for AWS Lambda","version":"0.1.1","private":false,"license":"MIT","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"dependencies":{"aws-serverless-express":"^3.0.2","body-parser":"^1.17.2","express":"^4.15.3","jsonwebtoken":"^7.4.1","reflect-metadata":"^0.1.10","uuid":"^3.0.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.16.3","@types/express":"^4.0.35","@types/jsonwebtoken":"^7.2.0","@types/node":"^7.0.33","@types/uuid":"^2.0.30","aws-sdk":"^2.67.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.3","gulp-sourcemaps":"^2.6.1","gulp-typescript":"^3.2.2","gulpclass":"^0.1.2","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","ts-node":"^3.3.0","typescript":"^2.5.2"},"homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.1","scripts":{},"_shasum":"259793e347efa81bd92d437e110c41a5ed5c7581","_from":".","_npmVersion":"3.10.10","_nodeVersion":"6.10.3","_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"dist":{"shasum":"259793e347efa81bd92d437e110c41a5ed5c7581","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.1.tgz","integrity":"sha512-ZYICk+aqT6eWjX3GM9qrlLszWQQSR7ywn/vYZQIZr6EWnsLNbdeDktvlCcKD8TKr2dMOI0OP5L9fxl3YfaBaGA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCD8OUhLcml/BJCwIgEvZlkKn/jtyOhwTuSd19U3exvMgIgY3MOHH9xvs7fOWHw7q06NMwq78fB/GobzsFW12dY7G8="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx-0.1.1.tgz_1509531426737_0.23528291005641222"},"directories":{}},"0.1.2":{"name":"tyx","description":"TyX Core Framework, Serverless back-end framework in TypeScript for AWS Lambda","version":"0.1.2","private":false,"license":"MIT","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"dependencies":{"aws-serverless-express":"^3.0.2","body-parser":"^1.17.2","express":"^4.15.3","jsonwebtoken":"^7.4.3","reflect-metadata":"^0.1.10","uuid":"^3.0.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.16.3","@types/express":"^4.0.35","@types/jsonwebtoken":"^7.2.3","@types/node":"^7.0.33","@types/uuid":"^2.0.30","aws-sdk":"^2.67.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.3","gulp-sourcemaps":"^2.6.1","gulp-typescript":"^3.2.2","gulpclass":"^0.1.2","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","ts-node":"^3.3.0","typescript":"^2.5.2"},"homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.2","scripts":{},"_shasum":"e9ad62f3a8b64d24e76c27f9032c3f3f1455335a","_from":".","_npmVersion":"3.10.10","_nodeVersion":"6.10.3","_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"dist":{"shasum":"e9ad62f3a8b64d24e76c27f9032c3f3f1455335a","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.2.tgz","integrity":"sha512-QJkkeBmkacS396YSG5CYKYHrmoMKACrDs96whoLDHQ0XO47I5xSI+a3b3KXqndW/bcyxbJGOqljHGPHsdFrQTw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGDQjwIDFBhChW9OY7XBLC7XEV5Ic1HdjLW3sBKUTrSCAiEAkfIvUuISECeWsIKQduYNYIIyF7pNoGWThYN4ZLiTlEs="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx-0.1.2.tgz_1509699111296_0.5032829393167049"},"directories":{}},"0.1.3":{"name":"tyx","description":"TyX Core Framework, Serverless back-end framework in TypeScript for AWS Lambda","version":"0.1.3","private":false,"license":"MIT","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"dependencies":{"aws-serverless-express":"^3.0.2","body-parser":"^1.17.2","express":"^4.15.3","jsonwebtoken":"^7.4.3","reflect-metadata":"^0.1.10","uuid":"^3.0.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.16.3","@types/express":"^4.0.35","@types/jsonwebtoken":"^7.2.3","@types/node":"^7.0.33","@types/uuid":"^2.0.30","aws-sdk":"^2.67.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.3","gulp-sourcemaps":"^2.6.1","gulp-typescript":"^3.2.2","gulpclass":"^0.1.2","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","ts-node":"^3.3.0","typescript":"^2.5.2"},"homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.3","scripts":{},"_shasum":"d5d30288a4dea5b1c99d353f193b317016c6e2ae","_from":".","_npmVersion":"3.10.10","_nodeVersion":"6.10.3","_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"dist":{"shasum":"d5d30288a4dea5b1c99d353f193b317016c6e2ae","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.3.tgz","integrity":"sha512-URmxM1LrbW6fcmHa7vo39hd057A0ZgrDsD881WbkSJZnLJ6nuZHkpYCityyJgqMBDIxu+NDEogOwnyb2n5M+Lw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFxfeKrfefWzhxm2qtXAWr5Vt1AbwC1PZ4STOy8OS1SaAiEAjYSBKhd2W57JmozgqdCtCOP3MZF8DtuptwoqcrL+Kx8="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx-0.1.3.tgz_1509964073152_0.48989637685008347"},"directories":{}},"0.1.4":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.4","private":false,"license":"MIT","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"dependencies":{"aws-serverless-express":"^3.0.2","body-parser":"^1.17.2","express":"^4.15.3","jsonwebtoken":"^7.4.3","reflect-metadata":"^0.1.10","uuid":"^3.0.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.16.3","@types/express":"^4.0.35","@types/jsonwebtoken":"^7.2.3","@types/node":"^7.0.33","@types/uuid":"^2.0.30","aws-sdk":"^2.67.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.3","gulp-sourcemaps":"^2.6.1","gulp-typescript":"^3.2.2","gulpclass":"^0.1.2","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","ts-node":"^3.3.0","typescript":"^2.5.2"},"homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.4","scripts":{},"_shasum":"13158f96af1847ce304c10a2f642de5216b397ad","_from":".","_npmVersion":"3.10.10","_nodeVersion":"6.10.3","_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"dist":{"shasum":"13158f96af1847ce304c10a2f642de5216b397ad","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.4.tgz","integrity":"sha512-lBor/7eAAad31/m7Dyb/tIaA0GCeEJVl+rCHZtig5r02m1zlihE4Z9QCkCH505S9SMNVOwjUHLCy8cRcWwvvpA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFSCc9hrekaQ3yA+WiWblzUDPVU/dXP4IuElOdxD3jNRAiBQzQbG+PmSvnoVmWoa7I1XfntCrsRDjgcq3tJ2RLcReA=="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx-0.1.4.tgz_1511441458396_0.2650783641729504"},"directories":{}},"0.1.5":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.5","private":false,"license":"MIT","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"scripts":{"package":"gulp package"},"dependencies":{"aws-serverless-express":"^3.2.0","body-parser":"^1.17.2","express":"^4.16.3","jsonwebtoken":"^7.4.3","reflect-metadata":"^0.1.12","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.16.8","@types/express":"^4.11.1","@types/jsonwebtoken":"^7.2.6","@types/node":"^7.0.61","@types/uuid":"^2.0.30","aws-sdk":"^2.224.1","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","ts-node":"^3.3.0","typescript":"^2.8.1"},"homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.5","_npmVersion":"5.6.0","_nodeVersion":"9.11.1","_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"dist":{"integrity":"sha512-8gRXLVh26U9PVGAmHEOURTYwzwO81ZvqFR9fYBqZwOAlMexuql3aPivPbOZwRlaXdE9kroF+QOUN4aDBnU6rhw==","shasum":"448973989920995c63d9a8fb7841b69df43ae067","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.5.tgz","fileCount":158,"unpackedSize":421449,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJa1yzLCRA9TVsSAnZWagAAcIYP/jzU9KClZcpqKuIAm6yw\nOf02/7ATZQN+L+lr/vxOS1a8ePEP4rtMwHzKiNkplxiA/wzMNkunvgR+hOUO\nTloaL+tfz9+FU8qiga/Xg2/J3+vmUEdl4FSO4uKcMHEDV+vXkZG9hwDklcQT\nqup1nQAM830ao3OEZYgxAV9cCoJ6V+B+fcRI3ya71jgIA+DqbhrE4CwgeKDf\nARO45CF/T2J9/4K1Oe/D0U8Kyl42xCz6BTheRanOEO4dluNEivNObZsTJ8vD\nmB8roFLQN8iwGNuYZ0odmeBYm7+yS3i1IAzSxgUu1z3rywXR0l8yoJhBifxK\ntn3IFB3TVJvVYdDS6KjSALcUj9AA2pKhTW2zBUsUc8w8/phJcLgizW+QYEue\nb22Q0rN98meDJidawkYlbGG/i0gm5G+6zYCSwhAoC0lZ8ZSaUwr4lLJ5Qglm\n4pAiFysE3eszkomoUH1hyxErLVa+HcE+fpPoNXV00utwtcR8nDh4k82zHv+Q\ntnMVjij/g4I3ZU/kQsOLkf5f44tIaA42ylmZ9J+t9V3UMpXUqZbbpvol0+iM\nhLdscSYpZRHtIHtxcPyuanrn9HhevKEcqlrO4YT/ULHUK/j93+a4LLdv4/Gp\nbQqsgk6adFCqyenlpgWRn103AsyZKKLvT3uzWLhsX4rniDr1t9YIYo+TiNdC\nYa0A\r\n=M739\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC79pIyqr5bklVO1a4NjribxBsfRGQRFUo+AS/fyVe4MgIhAMc78LjLXYwUZslm7I8YOw1x1LJqqzoJEpfGC3VoOm+X"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.5_1524051145107_0.6330782640156865"},"_hasShrinkwrap":false},"0.1.6":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.6","private":false,"license":"MIT","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"scripts":{"package":"gulp package"},"dependencies":{"aws-serverless-express":"^3.2.0","body-parser":"^1.17.2","express":"^4.16.3","jsonwebtoken":"^7.4.3","reflect-metadata":"^0.1.12","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.16.8","@types/express":"^4.11.1","@types/jsonwebtoken":"^7.2.6","@types/node":"^7.0.61","@types/uuid":"^2.0.30","aws-sdk":"^2.224.1","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","ts-node":"^3.3.0","typescript":"^2.8.1"},"homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.6","_npmVersion":"5.6.0","_nodeVersion":"9.11.1","_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"dist":{"integrity":"sha512-uQC6FesomT6kgT2dBTj+KLpIFpKB6gzSzH1mbugTJyRpJJHtxixdQf7empW48L8peQaB+9GLKj6u5OdOOlX9TQ==","shasum":"5544887f247aed79bf4a98a3e06b9e8e73fe9ce3","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.6.tgz","fileCount":158,"unpackedSize":421514,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJa2JO2CRA9TVsSAnZWagAAOfcP+QB0GGMwUsamIH9PRw9s\nsysWRXailMIm4U7BJ0VUCZ6CiZoARTUH8dkRF3dmFL4+UStFZA09N2Exhukl\nCo68gb2Wwcl803UriPukMKCYjJsxqYXZOn3UvxqI0f5e8H3QM1G5HPoIJ4V7\nmhkYjHnsBlC+0f/iYi9DuPJtMM+7j0GwK5H+cLN+kzRkl3uKWKsxMbGEwGOr\n6a0wMCW7NjCtTbAaUph9YbbNbdUe9qEQwoiLMftwjVEltVZB+IfudS/d/vJb\nvU8UXSgoAPX1n4oiUc0m50so8F2++JwlRbpalYnEqN6UwdzlfSakP3fNS4UC\nHQ+/rGdG4htxJwyUrReHlUfdnPzZr0dUzPdflQrVB5XprdzChKgolaiFapZG\nyh2hTnip+E/kaJS6fRpbpi9o2choYaO+iNEf2B6/nlRhQ+z1U8pcvTDckGe3\n6XGbkMRS1olvse1yRiXtqiQShLdWRkLxaqNas1/87kszhbZ+n++XcoiuSM/E\n+N7kXpBcb5LHzLAWh5zhwBPPIc+3x2Y3mPYHKdvlbr0ZDTsSPaKdw5WAat62\nvRqDcQVl0QUFDK93TErybImBO9Y5EKyN6otrOPclbviWtRCsW+grmZT8WZlc\nbBMPtVCsIvpoSZ8DwLPvKpMwrWQk6tZ80Vn586pQQ4/AjXhF9HHOvDDByfLs\nPkVA\r\n=0b/y\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFiFjx9j42zO9Gx538Bmn7ho6EmuOhOTdU835wv8xkfrAiANOAAGWMR05hpqtNLJXHHN7X9EsmLP0AvtgumpXX33Zw=="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.6_1524143027911_0.7042656173224002"},"_hasShrinkwrap":false},"0.1.7":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.7","private":false,"license":"MIT","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"scripts":{"package":"gulp package"},"dependencies":{"aws-serverless-express":"^3.2.0","body-parser":"^1.17.2","express":"^4.16.3","jsonwebtoken":"^7.4.3","reflect-metadata":"^0.1.12","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.16.8","@types/express":"^4.11.1","@types/jsonwebtoken":"^7.2.6","@types/node":"^7.0.61","@types/uuid":"^2.0.30","aws-sdk":"^2.224.1","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","ts-node":"^3.3.0","typescript":"^2.8.1"},"homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.7","_npmVersion":"5.6.0","_nodeVersion":"9.11.1","_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"dist":{"integrity":"sha512-Eyf3oLKP/oEQT93+cFOfTpbR/Sf9IDIcD1NIP1LY0C766LEHzBrBzyQXqp3diMmBkXJH+hdFg9a5Qtm4xR61nA==","shasum":"dddb82c525effb6839305a04a9c8999bc7ceece6","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.7.tgz","fileCount":158,"unpackedSize":421709,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJa2QQNCRA9TVsSAnZWagAAzM8P/0JBVPrA6tQEr6ddg/Uj\noOG9o732UKFQC2VpXk0147CLONwDyjeXgZxFH9gxaA5/8Xf/cqfBpHKHNR1D\nYMShg9xNZ7QBUt+ti4CHN6CVelL2rgs5EVin29yOK7xxzT9EzeenmH0lUX91\nWQscR2OI9Ytb9fhUSnwbXHBdR7ZJzmF3ZtfdGaEr4ioHttDDoqvyFfgOlob2\nPkYKlvTTXnN6VwJV4V55NEHCSszz4xktJEVs2/vhTnAtblTf0SQnJiaigR2+\nu3bLxbqXeVdJLgH8sTjKhkPqDETuOC1CxojCueBQFccigzdgYuPEQmH5VFCq\nM8pfoWBLkhFQEh3aAXmesrVkE688UP1T1JRXgv1qkETEflV3wlMBECDSkcVG\ny+LZD7R8RGQdQuEXQaQTRzI5LgOlJxowXV3HhMpBa72+GbxqFMWntcMtSS7l\nBxbLXab5Fru4LlMV1kgbYG0wSNSMjqnRBNQPz/Z6JaYZnsJrhWjv78kEHnfo\noWxjFlbxgBoCyGu28isICXsiIhcSxNUW+eGoUU2OGfhy+U42GI0FAVb1fwjn\njSCtKP9xb7a+CNlgODOv2/qCNHgcegw2nF+YSGzn/ELoXG+lKjL/74jU5pVG\nsc/xRHsMilgFV0aI3A/vHaprJ/FUAVSslmjdq2xnL/85RMdjPmKiGpTLFvj3\nR43z\r\n=aJeD\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC4moHGX4Bwg9MzvbsKc5K29XECk6eug+tYkKcuYjvUVwIgZZEI4nLu8NW7CjW1DZrbRIxmtDBYxaZKxl1zEo2XbVg="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.7_1524171785607_0.006501835739858297"},"_hasShrinkwrap":false},"0.1.8":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.8","private":false,"license":"MIT","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"scripts":{"package":"gulp package"},"dependencies":{"aws-serverless-express":"^3.2.0","body-parser":"^1.17.2","express":"^4.16.3","jsonwebtoken":"^7.4.3","ms":"^2.1.1","reflect-metadata":"^0.1.12","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.16.8","@types/del":"^3.0.1","@types/express":"^4.11.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/jsonwebtoken":"^7.2.6","@types/merge-stream":"^1.1.0","@types/ms":"^0.7.30","@types/node":"^7.0.61","@types/uuid":"^2.0.30","aws-sdk":"^2.228.1","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","ts-node":"^3.3.0","typescript":"^2.8.3"},"homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.8","_npmVersion":"6.0.0","_nodeVersion":"9.11.1","_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"dist":{"integrity":"sha512-XrdR72NG5VC9O3ObeZChK4i7aLCDmZMv0Ke8xAGl9ObSthRE7Q5dZIijqt8RJwieIa8WirPAu8aMnDHrSdjIjQ==","shasum":"7b77758ff57d2104dce07c257b55d6cd0d2b31a5","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.8.tgz","fileCount":158,"unpackedSize":427099,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJa35dzCRA9TVsSAnZWagAAXX8P/iczmAPXnkPTbtWLGujr\nlO1PLcO/zJsHMOQx5rwS0OExX3Q05OAJLJ8gaKOILpHxy3yLiYwKu0+7P2/g\nk1tmnkSsymaMMPXOsKsUSb+7n6tOD3KB1eN6+QbE4yBabDqyitw7ROf6MuHz\nfuwJIB5t9y7sr3kZnQLhQhnV1flU5U8PA+6bqeESVvSKvFurwZ7RyoO5aLrn\nXdl36a+TBbkqgelDjZBsJutF/vSXCjNSvHoJE0ZrEJkAJre4QdZRPJS+I51H\nhZ/Pi2yhxUqBt3plzFwFKQ9oUK+3uZrWhQzYh7VbHRwrY5AftwHPX6ZuWXTt\nk5hLoOJs9PenTfdv7bqlWgspLLT9yQFuWaBlnqsRNZQPZdlW/x+Q+t7frs/F\nRvRyLE5A8UwTOmgG9VKxsZhCbTTh//V8JhDdhk0HaRVofX+5Cu2wF3FyIsjE\nyRzEsl021qP4X0MSwy1e7/MevtPdbUoWrhjxuw18iKqd//cWRn6vNjnxmGvw\nDwwVEx/CSUsnVt7WpmMshMjUGLzhHVMrIN9z6jroSToXY9VBpo1XZdQAzYZn\nMKt5fRgfRfPX/iJkm7lH4Zxq29z9l1oUWu1HiCX5zpKOJmGyz2QxMuP19RJG\nKkQE9J0nl90lYyIZDQNFSnZW3QwcOprqMHZEHfVo4+MaWFWYP2hNxExeXrfa\nJ3qG\r\n=SjuP\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCZa5lEvpWsBh3h6YXlL53b2EsQaRD7FlSPtHYWz4qs7AIgaaT7s9m2j9qBAThxKm1N10+i7KRVYg9QAFidG2bThv4="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.8_1524602736859_0.7271422619864087"},"_hasShrinkwrap":false},"0.1.9":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.9","private":false,"license":"MIT","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"scripts":{"package":"gulp package"},"dependencies":{"aws-serverless-express":"^3.2.0","body-parser":"^1.17.2","express":"^4.16.3","jsonwebtoken":"^7.4.3","ms":"^2.1.1","reflect-metadata":"^0.1.12","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.16.8","@types/del":"^3.0.1","@types/express":"^4.11.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/jsonwebtoken":"^7.2.6","@types/merge-stream":"^1.1.0","@types/ms":"^0.7.30","@types/node":"^7.0.61","@types/uuid":"^2.0.30","aws-sdk":"^2.228.1","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","ts-node":"^3.3.0","typescript":"^2.8.3"},"homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.9","_npmVersion":"6.0.0","_nodeVersion":"9.11.1","_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"dist":{"integrity":"sha512-CLsF3xSWeWY+dGS9hAZlqIKwRxGedQeNdbDnH23ZBveE3pZZjcmD58kHCO/wX9OKlk7VtY3WR52Sy+HPBnCTlA==","shasum":"24abb6f70aacec32dfbff10b0e2d85f0866a0f0a","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.9.tgz","fileCount":158,"unpackedSize":427434,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJa36EHCRA9TVsSAnZWagAA+IEP/1fMKwara5brE3rhhOm0\nKFBPe9P7yLFswJJwqgxNT8a/1Oy+JqNtJpX/AhJwjQEwPYqaXIKRbpfhpVHo\nrKyMAyHx7+Pkmfrw232+ax+yoaj4nGQfbsjBYsKGL03iSnEOnyU2kK5DyBa+\nRepL55PC+s8N0UcnHzCr+TLEFuHolJTKdmEC6ioqZVPpTIi7NMWj7etYJMT9\nCQT4T13p7Z/vzhBvvhX5EIhXYDzkSs80qI+tsHawdZIR7W+Cp+p9Bw+14e6T\nN3rMXRqsvXPx5kmkmFjN2VyOaS+qVPPjJVGkaI4JQTjK86EOP7/ysfrcs5fe\nz6b17A0BkhQFxZdB/iqGPmLCP0aMSM/hkcS8spAdYod9XGvorht6Ho19rvaj\n81a2XwA8etNnr2xG0KbtL6mt+ekk28nPDbBdmqm4ZpBCXSrVHEcths+HlNnc\nI0JB81PO4EgLu2DUbhlBRsnyUE+aD7OL14xDQsJcMye+eZTcOAQJlrJnbMJB\nTRQzyNygWZeVXhX+JR8rFurO4fVshOti08UN+LESZZx9AJB5h2Y8tHRFKSnz\n3RcnB/Jfu5NFfgodZJEpN6f61s3vCYcleoUNAwsWJ+ZVoyZSLF7pRWVkJlt5\nwvT2UF+RTaFGXfB04zmTIK7UmPCphTS7XB7I+RuThmhBonzM4qRnSQGywmQF\nWhlr\r\n=xD/E\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDQ5YwlTVGrr8mUDSdt2LwI4gyD/idDlILxWF+AWASbQAIgJqlE4Mbs+wVAe9F54q9tnVHcR4Jm6Jd20LAyLBZDvzw="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.9_1524605189245_0.8245147625745894"},"_hasShrinkwrap":false},"0.1.10":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.10","private":false,"license":"MIT","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"scripts":{"package":"npx gulp package"},"dependencies":{"aws-serverless-express":"^3.2.0","body-parser":"^1.17.2","express":"^4.16.3","jsonwebtoken":"^7.4.3","ms":"^2.1.1","reflect-metadata":"^0.1.12","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.16.8","@types/del":"^3.0.1","@types/express":"^4.11.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/jsonwebtoken":"^7.2.6","@types/merge-stream":"^1.1.0","@types/ms":"^0.7.30","@types/node":"^7.0.61","@types/uuid":"^2.0.30","aws-sdk":"^2.228.1","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","ts-node":"^3.3.0","typescript":"^2.8.3"},"homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.10","_npmVersion":"6.0.0","_nodeVersion":"9.11.1","_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"dist":{"integrity":"sha512-64ngr0SJWdOR+B9Lwo8RqHoKq4CcxQDAqAJmbUD/BWDa8eLhKyIB92nSa7/FVFTIsBM5WZNq3V2dCg6RTVbptQ==","shasum":"0e02224a546f26a66fbcb786980a02b5b471613b","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.10.tgz","fileCount":158,"unpackedSize":430386,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJa8No8CRA9TVsSAnZWagAA+q4P/30jtq3mTDRhYpYF/xtl\n9AA7ZuYlLcsTJJwBj/OFf/CiuAXOVLzlrIVBEB3iUy6kdoxVv477LHlwpSgt\nlVifvtlZVgEFPA3fLq8GQjwM30/CeSq644f1WPnlhAJYWhj2ngeRxQVL1Kce\nhtAWFkNcIlDGDtLREKrIaMFB1b76GvDruhlOx2US3JSkPwD6LyinXJNHGvhV\nOLAGWdw//v/3Iha6e7LTIz9lJ6JOgr7kjSbe9JAwTR7880Xle9a5dNZX/cox\n2Agl08RY55W63mVxz4ntK1NXRjhMIhypTvqs6IbdCuly3HM7B8zkUuFLsXBb\neWN1EWc1a4PKNvLuTTZfgaNWxPPmfiEVTKJIm9YWhPebzqkcP2Dnlr3iWZXI\n54b9iFM7xgZIj79Qdb2xbhaMSQAAxxgUhRBM29oKWPWGSeDErB4OVuCTQk00\nXm15mgTr4F5JUB+VbH30Wy3PzBi6ZJfavfXr9XPleR4NzexcIfhns+9J0Up1\nWdYHfxqsVRVhdLegG98dC6Tw4bu5//TidKdn7fKk2u2Z5/nbxjebV6ksMsNa\n5149mTiHv3QZEoIH5N1n7U5g4VkCF2cYHZgazjfFwGQpVE2wGUcKPV8WO22V\nb6VnIAXu3UjcnoWthxvl88z7h1BjOvJA47N7JRLa4cAFODRqubRYM1lXw7QW\nqS81\r\n=YI7b\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIExEDVyITUA7GYzrG7sMQgA/SJHWKaoNy5bv6ONHigf0AiASe5qUwP18frZJAe8MJveHHlWaGggWTucXVpGm0yL4Xg=="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.10_1525733945574_0.1538095632383336"},"_hasShrinkwrap":false},"0.1.11":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.11","private":false,"license":"MIT","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"scripts":{"package":"npx gulp package","publish":"cd build/package && npm publish"},"dependencies":{"aws-serverless-express":"^3.2.0","body-parser":"^1.17.2","express":"^4.16.3","jsonwebtoken":"^7.4.3","ms":"^2.1.1","reflect-metadata":"^0.1.12","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/del":"^3.0.1","@types/express":"^4.11.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/jsonwebtoken":"^7.2.7","@types/merge-stream":"^1.1.0","@types/ms":"^0.7.30","@types/node":"^9.6.12","@types/uuid":"^2.0.30","aws-sdk":"^2.234.1","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","ts-node":"^3.3.0","typescript":"^2.8.3"},"homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.11","_npmVersion":"6.0.0","_nodeVersion":"9.11.1","_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"dist":{"integrity":"sha512-JpkcLBAqeaI2vcgRJxjag2EzDWjRAI+Q2VOP1J4cDY4NLFcVXs89gop1Pn93Q/Pgqr+va2Mm0oQ1zvJLUJBBQg==","shasum":"45c5d4a4d45b592df675160698696ec27b3c4dcf","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.11.tgz","fileCount":158,"unpackedSize":430343,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJa8N/SCRA9TVsSAnZWagAAVvIQAJGfVwpKE1tv8l7+AcLH\ns3h10OGCGiwH/M/+KXOoD/h3PRCNIAYRnnuPxQb9n9SGfsT9qy3+Cn3TQFcS\nUaXNGuGv1H+v8CMXaZQ63BOZg7YwawO/mVTu+bLkwoTOn4o9qts85vxHKuGV\nKAZ1mPE/TX3QUu9MJ/7heAux04AEAEvKBGr8Iakk+uHkM2vYM2/M3rqFQ4Wr\nOXsXGq890WVjw/7+kVi2+DwUh1q4bD6YHBSD20qqM73sIZq9KM2F47WUJqsm\nNQ3NQBXqDXQ8kAtdJ8HAKq80Z3Y3B2HfKJ1lViFfLiXYjSFdiScmPAu8KAEi\nP4HO9Vt7O9NYX/WbSFZ/qh0oV6pEDxTnbWlRdQQodKHNbypl6mfxudX5NsrJ\nRrVysnCxLkYnjrv94rbq2Gax7WDVhNBO1YW9LCQNHlgAFOj6vR7534cgHG9D\no6YlNV6RbnjOKXSxlAPEpoPLOBYO/pXNrviVhljoZ2Kx0eRmNXuyjoIlnquF\ncD/4LoTZx4Ni21bUVsqU0vOD3DnXG/teStN4GXK2FCtqN7DUn6KNxHt28X7F\nQAkimuxSvNutMAPHKBHSj1g2UQ744BR7UkrWAcFmdCtCrq7qXbsy+gL9lafd\n0bikOSkD7ChVds8NvGbULiTiDlmf9IZHoldHnAcPm4/6uDhpxGqCy2jMAUCo\nWF1l\r\n=H/PA\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCG8H748CxqBaen3dG7t4ez4eyMlHNE2tDrxtp8i3CWeQIhAO8lg7GUi5RAHfaqxQM4WhREZdXAA3btyfsJFFhKl1JV"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.11_1525735376403_0.8115241608960178"},"_hasShrinkwrap":false},"0.1.12":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.12","private":false,"license":"MIT","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"scripts":{"package":"npx gulp package","publish":"cd build/package && npm publish"},"dependencies":{"aws-serverless-express":"^3.2.0","body-parser":"^1.17.2","express":"^4.16.3","jsonwebtoken":"^7.4.3","ms":"^2.1.1","reflect-metadata":"^0.1.12","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/del":"^3.0.1","@types/express":"^4.11.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/jsonwebtoken":"^7.2.7","@types/merge-stream":"^1.1.0","@types/ms":"^0.7.30","@types/node":"^9.6.12","@types/uuid":"^2.0.30","aws-sdk":"^2.234.1","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","ts-node":"^3.3.0","typescript":"^2.8.3"},"homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.12","_npmVersion":"6.0.0","_nodeVersion":"9.11.1","_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"dist":{"integrity":"sha512-QJLzjl5c3EJ6+Wf/hqy88P2jwfBmbUOg4j2ET915EcBfj7Xk3vysqy3LREAu2EMTv8SOQXWTN5qYy8EA1mMEjw==","shasum":"d1cfd996fdc8652edeca4f551b5a608234960864","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.12.tgz","fileCount":158,"unpackedSize":430820,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJa8ORdCRA9TVsSAnZWagAALcYQAJJm260Txy3vKlamfUhT\npcQ7YSF33vMzySFT3B+3C1izZ51o13RAdBo0BLh3AFNOscebuGICYgaDDvLm\neIOfmYP2MbgbW586L86fS2SRvtA+O4xF6INM8NeKFVRY7GBQoXo7ofcI7nW1\nNbofRP2YtUlWPto+IqqThdk/ohfyuMcf5pQ7/AhGSly++yT8JpK7QvdurFUi\n2Eof8TgC46ziNPQ1Tjh5O7CJaekM6PhIdwXjXNATVNxLWEoQIHdI+Bnx/kMh\nu9QAr6zdcnGW5QreLTLSt9pUcRfKQxDaEFWp+Hr/iKCgpxTApwwk5QZ/vw66\nT9J6e88GmN4PQlR03Hna4iEQ0pu1J6K8zH10FMU6xssLmpTY02dP3yc9B4NO\n5dwgm/oGMSa7TTcUP56kXQdg+MZ8lxB9kvhVK5xqtK2hYG51qv8IuVhVGudL\nF4IetxIns0E6Bl9PmP4G2KQSJRt/DyPNv2+zv+6ck/Eplv3oVzEBdFug23hH\nG/XHzwmqg7qBF/2Dr3nJPL+qwmqZDbihIAidourP72kTfBUkqzLpE8sUSpCD\nWbESJPE0/YLVZ+1qdllsmyMkwetdoxc0j8bPzVxXJh7UVgWlEUVqmZbPMMwM\n32B9KtSkDvIgmxazEyZxhcF/Mxea2S7pPdJ3q9DjBRl5RHJDdWzyHA+Gshsm\npHGp\r\n=EBPP\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD9E2Y6rxHzNJOp+KOUuVfIaRrY3OQMLNQY53l5Oge3ywIhAJIEsrVooj0594Ir1h+0yIAYUZE6eRu92Xa6e0th/vh3"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.12_1525736539579_0.5314858878982958"},"_hasShrinkwrap":false},"0.1.13":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.13","private":false,"license":"MIT","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"scripts":{"package":"npx gulp package","publish":"cd build/package && npm publish"},"dependencies":{"aws-serverless-express":"^3.2.0","body-parser":"^1.17.2","express":"^4.16.3","jsonwebtoken":"^7.4.3","ms":"^2.1.1","reflect-metadata":"^0.1.12","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/del":"^3.0.1","@types/express":"^4.11.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/jsonwebtoken":"^7.2.7","@types/merge-stream":"^1.1.0","@types/ms":"^0.7.30","@types/node":"^9.6.12","@types/uuid":"^2.0.30","aws-sdk":"^2.234.1","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","ts-node":"^3.3.0","typescript":"^2.8.3"},"homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.13","_npmVersion":"6.0.0","_nodeVersion":"9.11.1","_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"dist":{"integrity":"sha512-lJzk/r0CTQF3x+MVBx+5xcYXX69rCL+7vo3pKTJj3c+qD8tz/x1I63ieWjgkKVGtLAeDPtt2XXdLZeLtTOHh7Q==","shasum":"2cd4ebc49c82625e3075075b82c4b7d632a1a38f","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.13.tgz","fileCount":158,"unpackedSize":431069,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJa8VGVCRA9TVsSAnZWagAAKo4P/1gDywWqv7RpnFy2GVvU\nWx1cREBIFJ8exiflI5Z9Dkzme27K65Hrpf5+YKB7uuxBWONm15Bsnb9rppIT\nz4gMpDaDvF1UI1yQ16WvSKvTnkzahI++znN2pFdR5mFIMBfpECSkpUqMAlR1\nG7eXWSmWIaH77kKiD5iaG6D6Ey8Cq7F7uu/VmXaSwYXrfeCRa6uWt4WrJs/b\nOTku06JHSu4s3OarbxfUW1Un1NrCPP4Z/s7GTU0BrOC/zFRLQd+qZL5eNVzS\n6RX8swaasESg7FHCO6POHHCzGPpxxKGgs95MkV5nvwgBoYQEt7K3H4eIvbui\ngOotWRE00d/JuemBEU8JKVGv9KdWlN2EiQv4JYNAgdDH2qkrGImOS6T4m0mK\n3+T0Ln6Vd4S+sCbu3vTyM7mvWXPWWnw23NQb6RJQ7qp4NPKZBL9eZbnkmmVf\ncvpGZMwmS9shKHySOJLbsJveJPD61WL+ODMwemNRL4/mHNM+bmYNOUx3Mp2H\naDfwG67x4+udBduFtTqTTSy9NiOLGRa1wGrzNSxMMeKrsVb7NJLv7x0cBm+H\neZF3SgAjUUGIEa9U2xGfvhNhTzDD37jVef4bmeJ8KvyzTj7pXYJoDAeRSP5Y\nEvcBR2egucOsqZxLaH0u3/8eOfjnx/x3oZjgvODn4ZksiAx2Jp+1VuKqbSDm\nb3b5\r\n=jSqj\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCmdQEtmNPEjAWycd252kSShBN+z621GnAal6YAz0r3TgIgP0l15gPmpchSM5NUWJyMrn8DQWrGAxDJiQL4tv9RvtI="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.13_1525764499832_0.18466407120231132"},"_hasShrinkwrap":false},"0.1.14":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.14","private":false,"license":"MIT","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"scripts":{"package":"npx gulp package"},"dependencies":{"aws-serverless-express":"^3.2.0","body-parser":"^1.17.2","express":"^4.16.3","jsonwebtoken":"^7.4.3","ms":"^2.1.1","reflect-metadata":"^0.1.12","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/del":"^3.0.1","@types/express":"^4.11.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/jsonwebtoken":"^7.2.7","@types/merge-stream":"^1.1.0","@types/ms":"^0.7.30","@types/node":"^9.6.12","@types/uuid":"^2.0.30","aws-sdk":"^2.234.1","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","ts-node":"^3.3.0","typescript":"^2.8.3"},"homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.14","_npmVersion":"6.0.0","_nodeVersion":"9.11.1","_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"dist":{"integrity":"sha512-aCQNXzkIuc1zFcBsSipU2v7O5DagmV2CjelIYccLfTTs86pNjZRMyYvmpT+naNPEh2frk0r+toCNXVKKxbXb0w==","shasum":"987a7c877b606b24531aa3d69114d36b25bc2ffc","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.14.tgz","fileCount":158,"unpackedSize":431119,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJa8YnvCRA9TVsSAnZWagAACOcP/RcBrTpup3m+q4ilGSa4\nA2h3N5Do3V78KKTPMNChyOXX9jiy54aFUR3eOnTRYdNwHZJ39GxRBst6SlHl\n5flLbeSd8oMpvRRVs170zih+S4qmzyR/fmpxzOMrDuzy+SXqe94arJdy0wPZ\nVoOq3Ny6+/Qmc0eFFs+tdzlBgMm3EU7TWYXHzetmoYJClPzmVulQ3kO625WZ\nSWp0Y8MqQAyeZGt4N3/05QCrKcU0KnCreguSuzkJ9/aQn/SQVlsC3Q8d7ayj\ntJ9GOnyl86EH7zOO2a1NYOnhiI3LvRb0srHv9p1sTiKxOxca3k//P97yEBCA\nggyXK2I/7F9YlZnigCVxn+/qcm9I+hVVl9mhJjfxuf2vrhGwfQ504K/GCTYd\nfQodybvDz/ZKKJtYUjWWeJThLhQvInilCI3HIZ6OIeN7ue4C9eOt3XVfiSOX\nhx4xze1KlxfD2ZkcDf14sSYY3hf0pe+UdOntVG6FZPs6ZOUjBmNnPWvNd97W\nWa4V8YDU6sKOyyV7fTsrpYBhfzhyJLWaMEnBgdZ4H+5wzLJnBgHN1tI4msJG\noOFBBjl9C15hWK2nlBImuCO6TAwFGM0459ytVFZyGLqyfa9m5VTluUQYMg1y\nHIbtbU3PsmMIwQCUYVleIzMtiLbuqC59DcopNz7YkZmw0klc097jABuIM4uK\nBLyQ\r\n=4SxZ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEbTZyouvv9oKi71CCpUDTLZXvXTX3DQMG/tbFvbIhLJAiEA4botc7IzENtzGP6staJWk1IFIbWBrXwklVuzsg4E5ts="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.14_1525778925787_0.22071773877173761"},"_hasShrinkwrap":false},"0.1.15":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.15","private":false,"license":"MIT","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"scripts":{"package":"npx gulp package"},"dependencies":{"aws-serverless-express":"^3.2.0","body-parser":"^1.17.2","express":"^4.16.3","jsonwebtoken":"^7.4.3","ms":"^2.1.1","reflect-metadata":"^0.1.12","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/del":"^3.0.1","@types/express":"^4.11.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/jsonwebtoken":"^7.2.7","@types/merge-stream":"^1.1.0","@types/ms":"^0.7.30","@types/node":"^9.6.14","@types/uuid":"^2.0.30","aws-sdk":"^2.235.1","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","ts-node":"^3.3.0","typescript":"^2.8.3"},"homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.15","_npmVersion":"6.0.0","_nodeVersion":"9.11.1","_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"dist":{"integrity":"sha512-/xQYCCEz4qbFj58wxZL7/BgTVIUCTanLkOos9gsKBNb211qI2WcdatjaYIKtW6kIxbE6PmF9N8MV5nW6/+dZeQ==","shasum":"0b74106d6d85d0287f5aba373da46ff8b09324d8","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.15.tgz","fileCount":158,"unpackedSize":430802,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJa8kLBCRA9TVsSAnZWagAAfeMP/3hc4kbAckGYRkiWUbCe\n88vjOZQcUp+p6BDnZ6U1Gg9kvRb55kHQwtHoPvrAibrxC5JIKRIhgnXlF+4N\nmtUIZU8gcvyrQOrlLqUBgzFfXkjY1xmWqsPha8jHOjW5MMIUIO7UtOEZ5Mjq\nj0uVL+tT/qgn1ZiduFBum/6ll1KP1zM4zT3R/JcqhcZP29kW3/T0mJuCMf9b\n6U9gLkgxqdRllTSGGcLkn13IiqRtOrPd8On3R59Aj5diRyNEPrvY7AgofSG/\nNJgeisvZv2NvX+OMsvqpnzEe8Er0NbOSigRBBVlCCmGXXsY660HkstMmdS7A\nLrBbeiXvVFJerxqmPTYNQfnfJ9av/vP8YSsOulVfH0gQtfXJKfFLYfESpXBc\n+AmgZ7XcGsNW5gxf8DZi9uD1kjC9SHTE6Lyoy3JnyOeg2YnLiHQJfNEL+sXX\nudAGzuHb0mw4KvRwm7Z3Vm1goe3mCmDmcZAimWg30672q8fQeU7vrvunnr4N\nVXomV/fiUXXgFCVmvEwbkBFhOX/lvjgfvBdldaOyc0cd71ZTIJILHsE1NEKY\nZvoPcgbKw6oX+n1a1WjL5pF6uoSc7R8RuNlNsmnBii7+MKlMvVgDjc9CTK6h\nx9EBvquzjpSblGrk201GQKImSgqlj4Y3lJcQbVN6V0ASbentcTpjiOD8Nw6g\neihO\r\n=01HT\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAmvNfjprdEdmMDnsrGw1kviCWxgzHYn6e9M/HacSUT+AiEAmdc3pRag/0WHEgzolKRGhJy8nOmg3wxqzERrLQ/ca7g="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.15_1525826239016_0.349084087051335"},"_hasShrinkwrap":false},"0.1.16":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.16","private":false,"license":"MIT","readmeFilename":"README.md","main":"dist/index.js","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"scripts":{"package":"npx gulp package"},"dependencies":{"aws-serverless-express":"^3.2.0","body-parser":"^1.17.2","express":"^4.16.3","jsonwebtoken":"^7.4.3","ms":"^2.1.1","reflect-metadata":"^0.1.12","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/del":"^3.0.1","@types/express":"^4.11.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/jsonwebtoken":"^7.2.7","@types/merge-stream":"^1.1.0","@types/ms":"^0.7.30","@types/node":"^9.6.14","@types/uuid":"^2.0.30","aws-sdk":"^2.235.1","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","ts-node":"^3.3.0","typescript":"^2.8.3"},"readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Call Object](#41-call-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP/REST Decorators](#6-httprest-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. RestAdapter function](#67-restadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @CallObject decorator](#710-callobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external calls. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function calls within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function calls are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote calls from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote call via `LambdaProxy`. The call is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote call is being prepared the secret for the target application is being used; when a remote a call is received the secret corresponding to the calling application is used to authorize the call.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all calls to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `REST_SECRET` that is used to sign and verify the web tokens as well as `REST_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REST_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    REST_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, call: RestCall): Promise<RestResult>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, call: RestCall): Promise<RestResult>;\n    onPost(ctx: Context, call: RestCall): Promise<RestResult>;\n    other(ctx: Context, call: RestCall): Promise<RestResult>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, call: RestCall): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    protected setup(app: Express, ctx: Context, call: RestCall): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.post(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.put(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.delete(\"/app/:id\", (req, res) => this.flush(req, res, ctx, call));\n    }\n\n    private flush(req: Request, res: Response, ctx: Context, call: RestCall) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: req.path,\n            method: req.method,\n            headers: req.headers,\n            params: req.params,\n            query: req.query,\n            body: req.body,\n            lambda: { ctx, call }\n        };\n        res.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Call object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Call object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Call object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Call Object and the Context Object\n\n### 4.1. Call Object\n\nThe `RestCall` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Call {\n    type: \"remote\" | \"internal\" | \"rest\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface RestCall extends Call {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: RestContentType;\n}\n\ninterface RestHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface RestContentType extends RestHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"rest\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP/REST Decorators\n\nHTTP/REST decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: RestAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `RAW` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface RestResult {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `RestAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and call objects to method arguments. When a `RestAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface RestAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        call?: RestCall,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `RestAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, call, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    call.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@CallObject` decorator\n\nTo inject directly the Call object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@CallObject() call: RestCall) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP/REST decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP/REST decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP/REST decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(call: RemoteCall): Promise<string>;\n    protected abstract invoke(call: RemoteCall): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(call: RemoteCall): Promise<string>;\n    protected invoke(call: RemoteCall): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    restCall(call: RestCall): Promise<RestResult>;\n    remoteCall(call: RemoteCall): Promise<any>;\n    eventCall(call: EventCall): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    restSecret: string;\n    restTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly restSecret: string;\n    public readonly restTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    restAuth(call: RestCall, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(call: RemoteCall, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(call: EventCall, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public restAuth(call: RestCall, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(call: RemoteCall, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(call: EventCall, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, call: RestCall): Promise<RestResult>;\n    protected abstract setup(app: Express, ctx: Context, call: RestCall): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.16","_npmVersion":"6.0.0","_nodeVersion":"9.11.1","_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"dist":{"integrity":"sha512-pfMPSVyg7SWlBAVaCDHjgQgBHWLjn3tnzOaze7QukcALIJu4ZknB/LZZZjnFYsQSRkij8lsap6PkjRosXzq97w==","shasum":"361cd41b7a766cac930ccfcf71787a4ef11d5ee6","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.16.tgz","fileCount":210,"unpackedSize":538542,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJa9JcjCRA9TVsSAnZWagAAAZ8P/ihHaizHE4ETCRWfjssA\na0gL48RGUnEovpeSFhtz5+6fKfYn1LtJa8IcOJQSUXe9KrafaS5UrFAVl/Y+\n3BP7GdrMLZ/ptmHM7uy1YAI9P2Ib9FMjPc2PlgEAIpVVL3FVlH0pDeenfRpE\nl3UchPVVAOQsRAXP/ibHpYYKe5OosAK85LoW9wRvW16CASgsb4qGyd3fFt23\n25rMgRmtA0VTiL9KtRazHUj+9BiHBKfKp1QqP9y2zA5n1kUY56keyXknLpwu\n/+ZzqOBeaW9krRwOdHTQYJ3VYy10Dif9ZY2PiRcfbQpQCJ+FpHVBnMWIKX0Z\njyQAr/OJ357XW0egMY7p73AXrn8/xzB+zHw1hGdYLxOMzkKJBxiOBy6cQXtX\n+SGHMD8jtJMHJhuEAE2O3SyLpHrPhfuty6LseQa6wPkHgB7wXyb/so/4JPhz\nir8gfHqF6erKoiUOUsYxETTO2KH2YUPBB4eDBok8YXYTPVn6wSQNyPVSl2OU\nhZCczN9ER6gI9ZY+Lt/haLd0KlAto6C2AnkoPUVDjQxFp17u4ilPOwJ9hmFE\nam35GLMGYKSGGrxdi1F0CdQlIoV1ECqSlPTNVcSTicRtssveaFzWgY55J2oh\nYNRQNzkkZ44VupQe22ojXj7Ss8y+imgowatL9e2YeDl7dLp3JLu4ri/46g00\nble+\r\n=69J0\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAatZTBW9odrcleO94exCgQQRT92BY7a6kuRUZ2vRAYOAiBy5BeYX5K3E6Dg822h5tfzuwclz4X2hwNP4SWX6iYbGQ=="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.16_1525978914347_0.9645036557172932"},"_hasShrinkwrap":false},"0.1.17":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.17","private":false,"license":"MIT","readmeFilename":"README.md","main":"lib/index.js","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"scripts":{"package":"npx gulp package"},"dependencies":{"aws-serverless-express":"^3.2.0","body-parser":"^1.17.2","express":"^4.16.3","jsonwebtoken":"^7.4.3","ms":"^2.1.1","reflect-metadata":"^0.1.12","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/del":"^3.0.1","@types/express":"^4.11.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/jsonwebtoken":"^7.2.7","@types/merge-stream":"^1.1.0","@types/ms":"^0.7.30","@types/node":"^9.6.14","@types/uuid":"^2.0.30","aws-sdk":"^2.236.1","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","ts-node":"^3.3.0","typescript":"^2.8.3"},"readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Call Object](#41-call-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP/REST Decorators](#6-httprest-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. RestAdapter function](#67-restadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @CallObject decorator](#710-callobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external calls. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function calls within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function calls are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote calls from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote call via `LambdaProxy`. The call is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote call is being prepared the secret for the target application is being used; when a remote a call is received the secret corresponding to the calling application is used to authorize the call.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all calls to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `REST_SECRET` that is used to sign and verify the web tokens as well as `REST_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REST_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    REST_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, call: RestCall): Promise<RestResult>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, call: RestCall): Promise<RestResult>;\n    onPost(ctx: Context, call: RestCall): Promise<RestResult>;\n    other(ctx: Context, call: RestCall): Promise<RestResult>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, call: RestCall): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    protected setup(app: Express, ctx: Context, call: RestCall): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.post(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.put(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.delete(\"/app/:id\", (req, res) => this.flush(req, res, ctx, call));\n    }\n\n    private flush(req: Request, res: Response, ctx: Context, call: RestCall) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: req.path,\n            method: req.method,\n            headers: req.headers,\n            params: req.params,\n            query: req.query,\n            body: req.body,\n            lambda: { ctx, call }\n        };\n        res.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Call object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Call object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Call object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Call Object and the Context Object\n\n### 4.1. Call Object\n\nThe `RestCall` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Call {\n    type: \"remote\" | \"internal\" | \"rest\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface RestCall extends Call {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: RestContentType;\n}\n\ninterface RestHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface RestContentType extends RestHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"rest\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP/REST Decorators\n\nHTTP/REST decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: RestAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `RAW` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface RestResult {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `RestAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and call objects to method arguments. When a `RestAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface RestAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        call?: RestCall,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `RestAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, call, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    call.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@CallObject` decorator\n\nTo inject directly the Call object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@CallObject() call: RestCall) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP/REST decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP/REST decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP/REST decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(call: RemoteCall): Promise<string>;\n    protected abstract invoke(call: RemoteCall): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(call: RemoteCall): Promise<string>;\n    protected invoke(call: RemoteCall): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    restCall(call: RestCall): Promise<RestResult>;\n    remoteCall(call: RemoteCall): Promise<any>;\n    eventCall(call: EventCall): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    restSecret: string;\n    restTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly restSecret: string;\n    public readonly restTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    restAuth(call: RestCall, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(call: RemoteCall, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(call: EventCall, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public restAuth(call: RestCall, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(call: RemoteCall, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(call: EventCall, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, call: RestCall): Promise<RestResult>;\n    protected abstract setup(app: Express, ctx: Context, call: RestCall): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.17","_npmVersion":"6.0.0","_nodeVersion":"9.11.1","_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"dist":{"integrity":"sha512-+59wvZaUq0lLs/uPf/4lX28qxH4LPqjdBwgxtMF2uIsKpYZrsztSK2D2vzD+1Ac2zgEDQcJWSgt9pyecIeISlw==","shasum":"f52703b1cb331bd13bd46172191ff45d6c7f639a","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.17.tgz","fileCount":210,"unpackedSize":538541,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJa9JneCRA9TVsSAnZWagAAf9wQAIAplpU7YFU4pGCjqfdM\ntvcvMws8sOJwWl+hcxjIvtgu1T0DFNg68t0QylI6b2H63RX+5yuDpINAqGEi\nbIJufFiuOuYhDR3Czf99A5F7TUDrXsHYRhg5fvlKCWG31rd/mCOazVOmzQYS\nGEvsH8Iw30wEivkgTvx0SxQ212/2kgyKXD6/n7UDONkVZwKYgEs0YVUX+8HK\npsw2QSP9XE8ESpyQ8BogRU9Hm6kEApvmkp49+yl8JisR4b1GgvDf85AUQW57\nzAlbEuznj5+MfKKfplSlL5B9liQx7kavXNz1uarzGSUGEa3PfNXZHGKTA2gf\nmONu9JwICZw1k0+4/fxbO5s6PeGhfpmCG2ORICzxbu3sUwZ7ife8e+0QdHL5\n+53qgnfH41K5pFi+mxVtV7qWA3COX5GCyZgpQn6mOgKSmAcUATlbz+ZyDORl\nXDEdZit7yD5XxkiawqF9FID7sYYbFVROhKB5GT5k5c++VryHSrvCJN09TvT8\nEd6qabkwT7eDZqVZ1LFu9AHxlwhxHkOg8y8ZD4VEm0kPSk9Ub2Cb1obgZzKz\nEIey8dCYx7MohPlEIUcoN7SRYEO+NRRT3VXH2TYmhcxPmBrC5o9PiQeoBLx8\nYx5yMYS625ypbFp0DdFKqJyPstlRRyEqVjPw+AzyysrnHS4QbEY2u8lVI90n\nJ7/u\r\n=fNjl\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDNNvfn1HXm04imje0gFzLKFOTOhJ24HgigGNqaOA+52AIhAMMsSv0ddC7EjIxy7waLDCOuXpfw7DnLvNjeTUxfjqOt"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.17_1525979613792_0.8647263729616419"},"_hasShrinkwrap":false},"0.1.18":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.18","private":false,"license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"main":"lib/index.js","typings":"lib/index.d.ts","typescript":{"definition":"lib/index.d.ts"},"scripts":{"package":"npx gulp package"},"dependencies":{"aws-serverless-express":"^3.2.0","body-parser":"^1.17.2","express":"^4.16.3","jsonwebtoken":"^7.4.3","ms":"^2.1.1","reflect-metadata":"^0.1.12","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/del":"^3.0.1","@types/express":"^4.11.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/jsonwebtoken":"^7.2.7","@types/merge-stream":"^1.1.0","@types/ms":"^0.7.30","@types/node":"^9.6.14","@types/uuid":"^2.0.30","aws-sdk":"^2.236.1","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","ts-node":"^3.3.0","typescript":"^2.8.3"},"readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Call Object](#41-call-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP/REST Decorators](#6-httprest-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. RestAdapter function](#67-restadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @CallObject decorator](#710-callobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external calls. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function calls within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function calls are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote calls from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote call via `LambdaProxy`. The call is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote call is being prepared the secret for the target application is being used; when a remote a call is received the secret corresponding to the calling application is used to authorize the call.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all calls to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `REST_SECRET` that is used to sign and verify the web tokens as well as `REST_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REST_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    REST_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, call: RestCall): Promise<RestResult>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, call: RestCall): Promise<RestResult>;\n    onPost(ctx: Context, call: RestCall): Promise<RestResult>;\n    other(ctx: Context, call: RestCall): Promise<RestResult>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, call: RestCall): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    protected setup(app: Express, ctx: Context, call: RestCall): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.post(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.put(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.delete(\"/app/:id\", (req, res) => this.flush(req, res, ctx, call));\n    }\n\n    private flush(req: Request, res: Response, ctx: Context, call: RestCall) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: req.path,\n            method: req.method,\n            headers: req.headers,\n            params: req.params,\n            query: req.query,\n            body: req.body,\n            lambda: { ctx, call }\n        };\n        res.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Call object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Call object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Call object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Call Object and the Context Object\n\n### 4.1. Call Object\n\nThe `RestCall` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Call {\n    type: \"remote\" | \"internal\" | \"rest\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface RestCall extends Call {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: RestContentType;\n}\n\ninterface RestHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface RestContentType extends RestHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"rest\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP/REST Decorators\n\nHTTP/REST decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: RestAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `RAW` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface RestResult {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `RestAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and call objects to method arguments. When a `RestAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface RestAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        call?: RestCall,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `RestAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, call, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    call.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@CallObject` decorator\n\nTo inject directly the Call object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@CallObject() call: RestCall) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP/REST decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP/REST decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP/REST decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(call: RemoteCall): Promise<string>;\n    protected abstract invoke(call: RemoteCall): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(call: RemoteCall): Promise<string>;\n    protected invoke(call: RemoteCall): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    restCall(call: RestCall): Promise<RestResult>;\n    remoteCall(call: RemoteCall): Promise<any>;\n    eventCall(call: EventCall): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    restSecret: string;\n    restTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly restSecret: string;\n    public readonly restTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    restAuth(call: RestCall, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(call: RemoteCall, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(call: EventCall, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public restAuth(call: RestCall, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(call: RemoteCall, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(call: EventCall, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, call: RestCall): Promise<RestResult>;\n    protected abstract setup(app: Express, ctx: Context, call: RestCall): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.18","_npmVersion":"6.0.0","_nodeVersion":"9.11.1","_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"dist":{"integrity":"sha512-JJBO7m0DhejG7L6jifLGFXYL3gzG7hTnvZo34yObzqz2a1vEGR3n9JtNbhTehgBardjWGnSWhEa0h+ouoLvr5g==","shasum":"05a5ffe154c86d60502aa522b485c26440e0fd7b","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.18.tgz","fileCount":210,"unpackedSize":538630,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJa9JvdCRA9TVsSAnZWagAAsQYP/2URQ20TGrY+5K47o6zV\nFyjMtpf2HpNE347Xl8N6YOs9AqRVhrHoR2TqPguXjrkbnPPDYhEW1w8n91hE\nQYAyIHFjfozBbz3akS0+wxdFDf3V3KjKw9yARRrBbmkTmtrlLCIMYWUxkMOk\noS/GKHeTgBRfvGU7GhwjljH3ufFcdYLHaEx0gruhd8iFwt0B6rQPYIaGUbv8\no1kpkap14gD/YzlYbDhZYvQGlSNUbkdTNzDxPQEo/KAAtEzxxJJ5/V1jGJzz\nzIvb8BXh2cJaJRUyCuEJsPZOTuQBYR3FtEFm+gjO5Wde/oNmO6UgTFuF1Frc\n9Vkwt77rpAKSfjemSB5inqYE6h2ApLe3I24AVsR+kpfXYnUinRhkbgT/pk6U\nWwsh/Wj+dFEkBu+ZOU2DHPDfzeLrFQFBpWfXq9Ak+0jvtFq79OwG7vwdp40n\n9Bb9qM8NrwuUy/tu9jBZxgbRecAFjR6prCDdvstDUZ6sh+9d+IJeiThTpoe8\n5/5ZMJChszHk74+ljJCtn9BKDUpD6UBgscg1tuwdLdKwVQImgIAJpPxEhEmH\n4IwjpJrn1h9RPxmE2WAovV7mpG33cHQlFF5jTyblYhmZMEm4mJaqmpKyYusf\nRnpgbAP/8T+Xm3YWRnybc81k2ZU6q8EA3B/c4oxOPVqrlne97EnB4aUTUII/\n96tZ\r\n=9E2p\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDwcgurM8N4/lC5sP6US4S3NaHJxrKVO8t1qyLu1LnchQIhAIr6VppPcAjayRdNcgAXwGmyw0m1YRFs3tTIx2/aeE+X"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.18_1525980125199_0.3364021088424374"},"_hasShrinkwrap":false},"0.1.19":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.19","private":false,"license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"main":"lib/index.js","typings":"lib/index.d.ts","typescript":{"definition":"lib/index.d.ts"},"scripts":{"package":"npx gulp package"},"dependencies":{"aws-serverless-express":"^3.2.0","body-parser":"^1.17.2","express":"^4.16.3","jsonwebtoken":"^7.4.3","ms":"^2.1.1","reflect-metadata":"^0.1.12","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/del":"^3.0.1","@types/express":"^4.11.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/jsonwebtoken":"^7.2.7","@types/merge-stream":"^1.1.0","@types/ms":"^0.7.30","@types/node":"^9.6.14","@types/uuid":"^2.0.30","aws-sdk":"^2.236.1","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","ts-node":"^3.3.0","typescript":"^2.8.3"},"readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Call Object](#41-call-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP/REST Decorators](#6-httprest-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. RestAdapter function](#67-restadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @CallObject decorator](#710-callobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external calls. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function calls within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function calls are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote calls from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote call via `LambdaProxy`. The call is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote call is being prepared the secret for the target application is being used; when a remote a call is received the secret corresponding to the calling application is used to authorize the call.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all calls to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `REST_SECRET` that is used to sign and verify the web tokens as well as `REST_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REST_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    REST_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, call: RestCall): Promise<RestResult>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, call: RestCall): Promise<RestResult>;\n    onPost(ctx: Context, call: RestCall): Promise<RestResult>;\n    other(ctx: Context, call: RestCall): Promise<RestResult>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, call: RestCall): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    protected setup(app: Express, ctx: Context, call: RestCall): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.post(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.put(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.delete(\"/app/:id\", (req, res) => this.flush(req, res, ctx, call));\n    }\n\n    private flush(req: Request, res: Response, ctx: Context, call: RestCall) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: req.path,\n            method: req.method,\n            headers: req.headers,\n            params: req.params,\n            query: req.query,\n            body: req.body,\n            lambda: { ctx, call }\n        };\n        res.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Call object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Call object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Call object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Call Object and the Context Object\n\n### 4.1. Call Object\n\nThe `RestCall` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Call {\n    type: \"remote\" | \"internal\" | \"rest\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface RestCall extends Call {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: RestContentType;\n}\n\ninterface RestHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface RestContentType extends RestHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"rest\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP/REST Decorators\n\nHTTP/REST decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: RestAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `RAW` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface RestResult {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `RestAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and call objects to method arguments. When a `RestAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface RestAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        call?: RestCall,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `RestAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, call, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    call.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@CallObject` decorator\n\nTo inject directly the Call object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@CallObject() call: RestCall) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP/REST decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP/REST decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP/REST decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(call: RemoteCall): Promise<string>;\n    protected abstract invoke(call: RemoteCall): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(call: RemoteCall): Promise<string>;\n    protected invoke(call: RemoteCall): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    restCall(call: RestCall): Promise<RestResult>;\n    remoteCall(call: RemoteCall): Promise<any>;\n    eventCall(call: EventCall): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    restSecret: string;\n    restTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly restSecret: string;\n    public readonly restTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    restAuth(call: RestCall, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(call: RemoteCall, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(call: EventCall, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public restAuth(call: RestCall, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(call: RemoteCall, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(call: EventCall, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, call: RestCall): Promise<RestResult>;\n    protected abstract setup(app: Express, ctx: Context, call: RestCall): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.19","_npmVersion":"6.0.0","_nodeVersion":"9.11.1","_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"dist":{"integrity":"sha512-Ohd1YRevgdtiuMuZXxSFCqRUiLYV722sk0hOPBJiGNXYos8TUu3UXvSYSZiqSSfLcDuRDzSPgBpKija2qTislg==","shasum":"29a88281c3f51160de3c8c60667db54f7d42941f","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.19.tgz","fileCount":210,"unpackedSize":540702,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJa9N4TCRA9TVsSAnZWagAANEoP/ArTBrjGdAlzltkT4WOT\ne7MEeQxJDnZo2WhKd4Si4PJ90ULCwO79Za16C5z+oVGutcmfwnD6VE/02Wl5\nmHPFlc3hWVVBfll7olEWDCYliVy3DJwKU9gGEyszKIdB6gV4qbs+pxw5TGQU\nY0waFHIyr6T9c3C9/RAof2wNRQ9YSoxHFlQd1z+1tSOlsXcwG7t1kXPSEBaH\nzcnUBdsureex8vsiQ4Cw+B57ntXkeOINiTeAJ+QekyRcQxaQBfVoeZaZdfIT\nS1ViAOSnvp9LSU9VmAD7/y1pX61aTaha5j9KJBHQt2AUHuPyyDghlYbDfGJx\nZk4IUj/xC11opO4jfQ9efV+8rygQ3pAcyxWj/8okA6V6AoRWgXOjOnZHetOW\nC171sm0+PD0jW0gyaKxtdD6oMFCt+2OQDSgiNNqWTkYLIHf5sFlADgH0/ucv\n1JnY8Su+2DvQZzagzmBe2/UfPB6egBkFQwzh6DbftaC6TB6r3oy0E22LyTCW\nlhWb/6Io+DHW7fljN3jKJaHRD9ryhSirw1M143GchQKeH26CPVENwev/vrEM\nvmlakeH/UBkC1jQlL+Xu+NZwMGzDLeBWwn2KRblKEz9/ZkCwjzamygZ5lDPp\ndEEOf9q3oEQWt2dpZ5yB24Df6hGTAjDlnh+ApvMcO82yK/r3ZVPTIo0LD/zn\nSENW\r\n=WBq0\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDGQ8007/DTmUg9HCnDCMBuWW5Ewt1kfhjAimPU6ed5bQIgNsP/0meiva6A/spuu612PQBdoFAmbPNze2Zm8p1OgM4="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.19_1525997074295_0.765522148720134"},"_hasShrinkwrap":false},"0.1.20":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.20","private":false,"license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"main":"lib/index.js","typings":"lib/index.d.ts","typescript":{"definition":"lib/index.d.ts"},"scripts":{"package":"npx gulp package"},"dependencies":{"aws-serverless-express":"^3.2.0","body-parser":"^1.17.2","express":"^4.16.3","jsonwebtoken":"^7.4.3","ms":"^2.1.1","reflect-metadata":"^0.1.12","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/del":"^3.0.1","@types/express":"^4.11.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/jsonwebtoken":"^7.2.7","@types/merge-stream":"^1.1.0","@types/ms":"^0.7.30","@types/node":"^9.6.15","@types/uuid":"^2.0.30","aws-sdk":"^2.238.1","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","ts-node":"^3.3.0","typescript":"^2.8.3"},"readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Call Object](#41-call-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP/REST Decorators](#6-httprest-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. RestAdapter function](#67-restadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @CallObject decorator](#710-callobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external calls. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function calls within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function calls are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote calls from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote call via `LambdaProxy`. The call is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote call is being prepared the secret for the target application is being used; when a remote a call is received the secret corresponding to the calling application is used to authorize the call.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all calls to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `REST_SECRET` that is used to sign and verify the web tokens as well as `REST_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REST_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    REST_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, call: RestCall): Promise<RestResult>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, call: RestCall): Promise<RestResult>;\n    onPost(ctx: Context, call: RestCall): Promise<RestResult>;\n    other(ctx: Context, call: RestCall): Promise<RestResult>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, call: RestCall): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    protected setup(app: Express, ctx: Context, call: RestCall): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.post(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.put(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.delete(\"/app/:id\", (req, res) => this.flush(req, res, ctx, call));\n    }\n\n    private flush(req: Request, res: Response, ctx: Context, call: RestCall) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: req.path,\n            method: req.method,\n            headers: req.headers,\n            params: req.params,\n            query: req.query,\n            body: req.body,\n            lambda: { ctx, call }\n        };\n        res.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Call object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Call object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Call object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Call Object and the Context Object\n\n### 4.1. Call Object\n\nThe `RestCall` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Call {\n    type: \"remote\" | \"internal\" | \"rest\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface RestCall extends Call {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: RestContentType;\n}\n\ninterface RestHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface RestContentType extends RestHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"rest\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP/REST Decorators\n\nHTTP/REST decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: RestAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `RAW` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface RestResult {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `RestAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and call objects to method arguments. When a `RestAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface RestAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        call?: RestCall,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `RestAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, call, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    call.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@CallObject` decorator\n\nTo inject directly the Call object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@CallObject() call: RestCall) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP/REST decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP/REST decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP/REST decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(call: RemoteCall): Promise<string>;\n    protected abstract invoke(call: RemoteCall): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(call: RemoteCall): Promise<string>;\n    protected invoke(call: RemoteCall): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    restCall(call: RestCall): Promise<RestResult>;\n    remoteCall(call: RemoteCall): Promise<any>;\n    eventCall(call: EventCall): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    restSecret: string;\n    restTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly restSecret: string;\n    public readonly restTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    restAuth(call: RestCall, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(call: RemoteCall, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(call: EventCall, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public restAuth(call: RestCall, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(call: RemoteCall, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(call: EventCall, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, call: RestCall): Promise<RestResult>;\n    protected abstract setup(app: Express, ctx: Context, call: RestCall): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.20","_npmVersion":"6.0.1","_nodeVersion":"9.11.1","_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"dist":{"integrity":"sha512-ltVYXpMJTNKcslau04WwCszGAUO1Lsx+ZdpQNeB3Juh56IRyo3SwoLRIpQ7XB/TC/QzsvzNa2Oa3LS/PbWDgFg==","shasum":"7c3d4bfcfcb90e8209b0ac1c3a6611e766ff2b82","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.20.tgz","fileCount":210,"unpackedSize":541449,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJa9s+zCRA9TVsSAnZWagAAFDQQAJKID4VDCWw1WZe4Vav3\nfoZTQ+OJS+P66miITXWVnF4EVduHwgJyoHvnQ8OMywwcX/wJv7Jtbrigl0SR\nqV7/r++S5zuq+mQaWePsnbpyKMD6z2GzIp5ZWPp2woHCwA8CVdELKbfenpho\nnnnHmUpG0aC8Nj3vdOgfdpWfHH1Lnsj09md7+NbNnPDmNw66X3ys6by/7FRn\nlMqUckTvBP+rT/hDtd3pVodoEsyajmsL94Znf7rHAx9oQEWi71V7IzdFCjXb\nj4ke/EeZOWSthPrdzES8gaW+zGpdcKLpuc7ndg7bA2MyCNw5KbyCmvYPdjOq\nXu5/Nan5nGmwYGhnbllSGPcpC6JgOjGf75ZbadsUs6v++G9jvdZg0KMaiFCy\nKu/czovlg9QnPD5tcNPWo2cAByI4K9XfogWZvqeNKRs6LkTnMRh72uL2Vp88\nMfMcqBIEnz5ODSHB79nB/SpeInFrULzcP1jSN3AtefMjlByy3+rBXG7TCQzP\nekLXdepRow3jrZsXflPIGD0z+ieKSRkt8Nn8aWFPhiHHOUdZKP31bKZiynRX\nMBs09GFWFCo8QaRiOUCPJyfoqKPKuVEALVC4tjl4n06IjWyx7bTfteBHrDlW\nHqQkpbpK6T3vlnw2CfwbL8MvE6amRoQpQ2uEMegqVohXUiJtu7dA12hAspdY\nm55b\r\n=IwBC\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDGndq48gYtJk396NM2B/GommHVc7lMQzehNH3XOzxezwIgf19cwpht1tGL9qGD2u+JXXXM/A1Z96IIaJc1+eTJuD4="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.20_1526124466984_0.5592947711264762"},"_hasShrinkwrap":false},"0.1.21":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.21","private":false,"license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"main":"lib/index.js","typings":"lib/index.d.ts","typescript":{"definition":"lib/index.d.ts"},"scripts":{"build":"npx typescript","package":"npx gulp package","publish":"npx gulp publish","publish-beta":"npx gulp publish-beta","publish-next":"npx gulp publish-next"},"dependencies":{"aws-serverless-express":"^3.2.0","body-parser":"^1.17.2","express":"^4.16.3","jsonwebtoken":"^7.4.3","ms":"^2.1.1","reflect-metadata":"^0.1.12","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/del":"^3.0.1","@types/express":"^4.11.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/jsonwebtoken":"^7.2.7","@types/merge-stream":"^1.1.0","@types/ms":"^0.7.30","@types/node":"^9.6.15","@types/uuid":"^2.0.30","aws-sdk":"^2.238.1","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","ts-node":"^3.3.0","typescript":"^2.8.3"},"readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Call Object](#41-call-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP/REST Decorators](#6-httprest-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. RestAdapter function](#67-restadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @CallObject decorator](#710-callobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external calls. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function calls within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function calls are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote calls from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote call via `LambdaProxy`. The call is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote call is being prepared the secret for the target application is being used; when a remote a call is received the secret corresponding to the calling application is used to authorize the call.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all calls to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `REST_SECRET` that is used to sign and verify the web tokens as well as `REST_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REST_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    REST_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, call: RestCall): Promise<RestResult>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, call: RestCall): Promise<RestResult>;\n    onPost(ctx: Context, call: RestCall): Promise<RestResult>;\n    other(ctx: Context, call: RestCall): Promise<RestResult>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, call: RestCall): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    protected setup(app: Express, ctx: Context, call: RestCall): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.post(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.put(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.delete(\"/app/:id\", (req, res) => this.flush(req, res, ctx, call));\n    }\n\n    private flush(req: Request, res: Response, ctx: Context, call: RestCall) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: req.path,\n            method: req.method,\n            headers: req.headers,\n            params: req.params,\n            query: req.query,\n            body: req.body,\n            lambda: { ctx, call }\n        };\n        res.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Call object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Call object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Call object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Call Object and the Context Object\n\n### 4.1. Call Object\n\nThe `RestCall` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Call {\n    type: \"remote\" | \"internal\" | \"rest\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface RestCall extends Call {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: RestContentType;\n}\n\ninterface RestHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface RestContentType extends RestHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"rest\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP/REST Decorators\n\nHTTP/REST decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: RestAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `RAW` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface RestResult {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `RestAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and call objects to method arguments. When a `RestAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface RestAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        call?: RestCall,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `RestAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, call, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    call.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@CallObject` decorator\n\nTo inject directly the Call object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@CallObject() call: RestCall) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP/REST decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP/REST decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP/REST decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(call: RemoteCall): Promise<string>;\n    protected abstract invoke(call: RemoteCall): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(call: RemoteCall): Promise<string>;\n    protected invoke(call: RemoteCall): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    restCall(call: RestCall): Promise<RestResult>;\n    remoteCall(call: RemoteCall): Promise<any>;\n    eventCall(call: EventCall): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    restSecret: string;\n    restTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly restSecret: string;\n    public readonly restTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    restAuth(call: RestCall, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(call: RemoteCall, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(call: EventCall, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public restAuth(call: RestCall, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(call: RemoteCall, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(call: EventCall, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, call: RestCall): Promise<RestResult>;\n    protected abstract setup(app: Express, ctx: Context, call: RestCall): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.21","_npmVersion":"6.0.1","_nodeVersion":"9.11.1","_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"dist":{"integrity":"sha512-hyq3CHOZj0x8BSlNDsDP6GkTpcG2sw7JJ4gWNFqBWeBghXdC8bumOAedEAEYyuv1FCQFvx6nrGKmtOxdMfUJKQ==","shasum":"f6f1b0dcce362176dcc60a585edd11ed392893f3","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.21.tgz","fileCount":210,"unpackedSize":541888,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJa9ttyCRA9TVsSAnZWagAAYs8P/iZ/1bEvd1Dpzol7xMLD\naBC2KHjf2+DEwK24vx382TIaVROHYXAzOvFzd5D2TvRcBPC4V++UYHxrB+nX\nhgWcqoAUCcgYWX+a27DpecxOilqDOZh2j+izhryf1ICPk3+Idqw1o56GlRnx\nXikAMqY82+HKYsRLW+CLNPc8bE7ESUM9S4G1FIswopL+cpIJ8wmwwvV0TRP5\njrhxUnVQtKxcsJu5jKA/2Pf6imPvdmfCnK0/9PqzKryBYBSkT+QJa9oFdGD1\nhhhiq9Im/pSPAF/8FPCggQ2bi54nzEFJMnqliz9tRYPZpFxM3ZINqc3jo/BU\nv8J0i2xRhWU4r8DoZnJEQX7eRJ+hPZImnbQoBee0misFWlZAEy30QDT6O/Oa\ngvvxsFexHNaANRUdIt/R1ikQZA1OVoH+YHfH4SXetNHNJIDJaK9Ka15/lsB3\njiA1wyoY53PtKVrYNdrqjzqWudMZpMgqTblh3S9DURXQQiP5aBYx9zlxfyns\nUDyQTga9aSiG9MavpLboOhyW0Lfr46w1GrXK6aeqPlxAcVLju23XIAM73ygH\naEeNTINz/e3FKal/HZbHSvSnQzWeTTcxhx3FFjMygGIpvJxvARUeeT5KXe3g\nduQN86v9H+Hhp9hbbhABN4bBmir24TBbgg/8nY4k9cPNnhCzMwTMhOdbhh2A\nAzme\r\n=nMbO\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFvZrLMX262kqEBrKs8pKxT/3tvjCqM1L3zAlR6MWJmrAiEA8WQ+K994WRRJar02aa/AmvVd3XkSuEpbyraY2QOu9O8="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.21_1526127474262_0.9690849009486069"},"_hasShrinkwrap":false},"0.1.22":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.22","private":false,"license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"main":"lib/index.js","typings":"lib/index.d.ts","typescript":{"definition":"lib/index.d.ts"},"scripts":{"build":"npx typescript","package":"npx gulp package","publish":"npx gulp publish","publish-beta":"npx gulp publish-beta","publish-next":"npx gulp publish-next"},"dependencies":{"aws-serverless-express":"^3.2.0","body-parser":"^1.17.2","express":"^4.16.3","jsonwebtoken":"^7.4.3","ms":"^2.1.1","reflect-metadata":"^0.1.12","typeorm":"^0.2.5","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/del":"^3.0.1","@types/express":"^4.11.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/jsonwebtoken":"^7.2.7","@types/merge-stream":"^1.1.0","@types/ms":"^0.7.30","@types/node":"^9.6.15","@types/uuid":"^2.0.30","aws-sdk":"^2.238.1","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","ts-node":"^3.3.0","typescript":"^2.8.3"},"readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Call Object](#41-call-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP/REST Decorators](#6-httprest-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. RestAdapter function](#67-restadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @CallObject decorator](#710-callobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external calls. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function calls within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function calls are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote calls from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote call via `LambdaProxy`. The call is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote call is being prepared the secret for the target application is being used; when a remote a call is received the secret corresponding to the calling application is used to authorize the call.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all calls to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `REST_SECRET` that is used to sign and verify the web tokens as well as `REST_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REST_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    REST_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, call: RestCall): Promise<RestResult>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, call: RestCall): Promise<RestResult>;\n    onPost(ctx: Context, call: RestCall): Promise<RestResult>;\n    other(ctx: Context, call: RestCall): Promise<RestResult>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, call: RestCall): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    protected setup(app: Express, ctx: Context, call: RestCall): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.post(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.put(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.delete(\"/app/:id\", (req, res) => this.flush(req, res, ctx, call));\n    }\n\n    private flush(req: Request, res: Response, ctx: Context, call: RestCall) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: req.path,\n            method: req.method,\n            headers: req.headers,\n            params: req.params,\n            query: req.query,\n            body: req.body,\n            lambda: { ctx, call }\n        };\n        res.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Call object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Call object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Call object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Call Object and the Context Object\n\n### 4.1. Call Object\n\nThe `RestCall` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Call {\n    type: \"remote\" | \"internal\" | \"rest\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface RestCall extends Call {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: RestContentType;\n}\n\ninterface RestHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface RestContentType extends RestHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"rest\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP/REST Decorators\n\nHTTP/REST decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: RestAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `RAW` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface RestResult {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `RestAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and call objects to method arguments. When a `RestAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface RestAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        call?: RestCall,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `RestAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, call, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    call.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@CallObject` decorator\n\nTo inject directly the Call object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@CallObject() call: RestCall) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP/REST decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP/REST decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP/REST decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(call: RemoteCall): Promise<string>;\n    protected abstract invoke(call: RemoteCall): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(call: RemoteCall): Promise<string>;\n    protected invoke(call: RemoteCall): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    restCall(call: RestCall): Promise<RestResult>;\n    remoteCall(call: RemoteCall): Promise<any>;\n    eventCall(call: EventCall): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    restSecret: string;\n    restTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly restSecret: string;\n    public readonly restTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    restAuth(call: RestCall, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(call: RemoteCall, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(call: EventCall, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public restAuth(call: RestCall, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(call: RemoteCall, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(call: EventCall, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, call: RestCall): Promise<RestResult>;\n    protected abstract setup(app: Express, ctx: Context, call: RestCall): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.22","_npmVersion":"6.0.1","_nodeVersion":"9.11.1","_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"dist":{"integrity":"sha512-jEUn8MAjlV0vAK0S5KR6q4/Ll3YLezBIpUF9LYKkf5aQuOsl97kaiHFHc146vFn+GoVnOQXYNFJYFjW+EEYKBg==","shasum":"fc5685ed94675f1876e9faf93fb79c4bbf6cf0a4","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.22.tgz","fileCount":218,"unpackedSize":557425,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJa9u+kCRA9TVsSAnZWagAAGVAP/j0zY66EG5qlWoIUoXIm\nL5IX3+AnFBzKd3DzIVcNd0wjQBZLw5Z58Wq92ph6vYY8rhAzfZmCUJzLexsQ\ns9Y3IzBYH6DS70qOA6FGtLv2uXIYMGXgZW6voyP0zs5Q4D3Tp4pNkv8n+UcG\nUjeqip6a5mUcy4dKxrI+2NVpqN2r5tq1+860OENpqwgGzBvFn74OtP4onzNe\nDzRj24koAgc0NEnDuA/eUKDCBu3ikpkuPSC77hLHvHxVTKkUbRDJbIjCfg7U\nFFZ4YtIgqqph7mrh2LiHQiu6K6vLt3HYB3uWzWV6Y0Tx+mmJ8XMD9reRV1Ht\nHdS6QI9BMxaBGcJk4R4fo6FaOVR7NF5FvNp+4/jHD3onEm09f8ZbSHFTAhMk\nwynZmKpY/xBWy5DfA+XFBU9ccwTe3fvCBnAP2MHtxzj08Y5Rb7aMft4GbZnX\nEf1fniwSmGxULTZ9A5/aDJGbKJ2zVhV7jb4nTTdjzHvH3gPcXZOavctSdaCi\nkUfqNkDl7idey3KwA1FzgX3/WP1pXNEnuBWWL0Z3v+DRpTxEhtslLMFykwzB\nEtIc6h5I/1+4qKOKtY+FvhD1rjQZvhIesVIb/r2dxswZXETxoE/SSXUjXjP7\nOOCrHYoZ1XjIvwotN/vq84VK+9lPsK4x19W4BVds+82VuNSjvl5u4xKLPdQy\nBwKW\r\n=j1KK\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC75sH+G1cWvHKXrpGYJ4fIJEDWh1gWplRGKLw2HBUyaQIhAMK4GivEZ9Dsct1GWcFPwuhJy/GXuG3f2oDfWJ0kqP4J"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.22_1526132643377_0.9573106657924837"},"_hasShrinkwrap":false},"0.1.23":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.23","private":false,"license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"main":"index.js","typings":"index.d.ts","typescript":{"definition":"index.d.ts"},"scripts":{"build":"npx typescript","package":"npx gulp package","publish":"npx gulp publish","publish-beta":"npx gulp publish-beta","publish-next":"npx gulp publish-next"},"dependencies":{"aws-serverless-express":"^3.2.0","body-parser":"^1.17.2","express":"^4.16.3","jsonwebtoken":"^7.4.3","ms":"^2.1.1","reflect-metadata":"^0.1.12","typeorm":"^0.2.5","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/del":"^3.0.1","@types/express":"^4.11.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/jsonwebtoken":"^7.2.7","@types/merge-stream":"^1.1.0","@types/ms":"^0.7.30","@types/node":"^9.6.15","@types/uuid":"^2.0.30","aws-sdk":"^2.238.1","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","ts-node":"^3.3.0","typescript":"^2.8.3"},"readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Call Object](#41-call-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP/REST Decorators](#6-httprest-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. RestAdapter function](#67-restadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @CallObject decorator](#710-callobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external calls. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function calls within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function calls are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote calls from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote call via `LambdaProxy`. The call is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote call is being prepared the secret for the target application is being used; when a remote a call is received the secret corresponding to the calling application is used to authorize the call.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all calls to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `REST_SECRET` that is used to sign and verify the web tokens as well as `REST_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REST_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    REST_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, call: RestCall): Promise<RestResult>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, call: RestCall): Promise<RestResult>;\n    onPost(ctx: Context, call: RestCall): Promise<RestResult>;\n    other(ctx: Context, call: RestCall): Promise<RestResult>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, call: RestCall): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    protected setup(app: Express, ctx: Context, call: RestCall): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.post(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.put(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.delete(\"/app/:id\", (req, res) => this.flush(req, res, ctx, call));\n    }\n\n    private flush(req: Request, res: Response, ctx: Context, call: RestCall) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: req.path,\n            method: req.method,\n            headers: req.headers,\n            params: req.params,\n            query: req.query,\n            body: req.body,\n            lambda: { ctx, call }\n        };\n        res.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Call object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Call object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Call object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Call Object and the Context Object\n\n### 4.1. Call Object\n\nThe `RestCall` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Call {\n    type: \"remote\" | \"internal\" | \"rest\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface RestCall extends Call {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: RestContentType;\n}\n\ninterface RestHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface RestContentType extends RestHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"rest\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP/REST Decorators\n\nHTTP/REST decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: RestAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `RAW` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface RestResult {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `RestAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and call objects to method arguments. When a `RestAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface RestAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        call?: RestCall,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `RestAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, call, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    call.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@CallObject` decorator\n\nTo inject directly the Call object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@CallObject() call: RestCall) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP/REST decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP/REST decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP/REST decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(call: RemoteCall): Promise<string>;\n    protected abstract invoke(call: RemoteCall): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(call: RemoteCall): Promise<string>;\n    protected invoke(call: RemoteCall): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    restCall(call: RestCall): Promise<RestResult>;\n    remoteCall(call: RemoteCall): Promise<any>;\n    eventCall(call: EventCall): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    restSecret: string;\n    restTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly restSecret: string;\n    public readonly restTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    restAuth(call: RestCall, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(call: RemoteCall, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(call: EventCall, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public restAuth(call: RestCall, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(call: RemoteCall, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(call: EventCall, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, call: RestCall): Promise<RestResult>;\n    protected abstract setup(app: Express, ctx: Context, call: RestCall): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.23","_npmVersion":"6.0.1","_nodeVersion":"9.11.1","_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"dist":{"integrity":"sha512-m5s158jME+t8Yznn5Qt5nKRwFqWhMHVq0/gUqKDB3cDK5M+wYaTPIUkCuVR2w9/14ARcmgBQo1/mf0GmOVxMDg==","shasum":"eced845f3c632f74027265287a89bf421de1b084","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.23.tgz","fileCount":218,"unpackedSize":557416,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJa9vTCCRA9TVsSAnZWagAAjSgP/1I7ok1fGbLJLQHRN71G\nWfkk6wuECPIQ8haZWrVILUlztW929cvBXCPO1BBp4mINnCNQLKKh+4WGae9V\nEOsDzgFp72dT3MKgbRqeGP21EiDRuaHboUr9QJHSbpcPpMvMyoiFRJrsF+Aj\nHlySZZZZ+ANHKaJihXCmZdPHNGivg0oUm9e8jez4tkxJ55EIhuk3fp7Fjp0R\nn22V0+lJGennvWx4FMKWjh1gQvRVSX8t+P4+x/ELi43uuCPa7MU3O4+a2I8B\n3242vPZ7G53W81TfBbEfsmKSIMW8I2NJLYt2qTF4uVpfhUSwFeP4HeSr4O3a\n/B0SY2Bdv2Nm20BhqBhljAhHLpNJTxqCwrxyE5XgASUlIGYUw12Rsw8j45y+\nTa614y49GlogVYaBQ4bZxgtJ9T4Aj/QcPtbH1zCxOMwlxSqgiBgZjGF7DRhe\nQGO3kyJb121czQsK0n8m+rR6ZDDKRXHBIfLK2e0qasxAqw/YOEP6g5MC4rfZ\n4IWKO8G9UvkgN2as3TP+aMoU3+ShRCOnXmrvMjcbWCpaWL1favAZFyR/OOSe\nZh1DEAuwl3xZtuM1s80t/u447GupxF5X3JdRYkHCqb43LKBNMLck9mWuwN2L\nLI7AIsrpX1kjyDyOPDSOlPGcGD1TFg40utKLNy16ERyuByAiXZUAGg1bI331\njWD3\r\n=8/H1\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIE+IfTNvi6V4sY1t2pUU7Nb65PkJ4DcuVSQQZMcdetOLAiEAqfvo5P8uQUfqyhnRQRi6Igy361VGe0iaAvzfKU2ophQ="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.23_1526133953642_0.5025335971055849"},"_hasShrinkwrap":false},"0.1.24":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.24","private":false,"license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"main":"index.js","typings":"index.d.ts","typescript":{"definition":"index.d.ts"},"scripts":{"build":"npx typescript"},"dependencies":{"aws-serverless-express":"^3.2.0","body-parser":"^1.17.2","express":"^4.16.3","jsonwebtoken":"^7.4.3","ms":"^2.1.1","reflect-metadata":"^0.1.12","typeorm":"^0.2.5","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/del":"^3.0.1","@types/express":"^4.11.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/jsonwebtoken":"^7.2.7","@types/merge-stream":"^1.1.0","@types/ms":"^0.7.30","@types/node":"^9.6.15","@types/uuid":"^2.0.30","aws-sdk":"^2.238.1","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","ts-node":"^3.3.0","typescript":"^2.8.3"},"readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Call Object](#41-call-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP/REST Decorators](#6-httprest-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. RestAdapter function](#67-restadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @CallObject decorator](#710-callobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external calls. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function calls within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function calls are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote calls from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote call via `LambdaProxy`. The call is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote call is being prepared the secret for the target application is being used; when a remote a call is received the secret corresponding to the calling application is used to authorize the call.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all calls to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `REST_SECRET` that is used to sign and verify the web tokens as well as `REST_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REST_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    REST_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, call: RestCall): Promise<RestResult>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, call: RestCall): Promise<RestResult>;\n    onPost(ctx: Context, call: RestCall): Promise<RestResult>;\n    other(ctx: Context, call: RestCall): Promise<RestResult>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, call: RestCall): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    protected setup(app: Express, ctx: Context, call: RestCall): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.post(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.put(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.delete(\"/app/:id\", (req, res) => this.flush(req, res, ctx, call));\n    }\n\n    private flush(req: Request, res: Response, ctx: Context, call: RestCall) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: req.path,\n            method: req.method,\n            headers: req.headers,\n            params: req.params,\n            query: req.query,\n            body: req.body,\n            lambda: { ctx, call }\n        };\n        res.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Call object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Call object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Call object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Call Object and the Context Object\n\n### 4.1. Call Object\n\nThe `RestCall` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Call {\n    type: \"remote\" | \"internal\" | \"rest\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface RestCall extends Call {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: RestContentType;\n}\n\ninterface RestHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface RestContentType extends RestHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"rest\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP/REST Decorators\n\nHTTP/REST decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: RestAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `RAW` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface RestResult {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `RestAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and call objects to method arguments. When a `RestAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface RestAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        call?: RestCall,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `RestAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, call, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    call.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@CallObject` decorator\n\nTo inject directly the Call object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@CallObject() call: RestCall) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP/REST decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP/REST decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP/REST decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(call: RemoteCall): Promise<string>;\n    protected abstract invoke(call: RemoteCall): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(call: RemoteCall): Promise<string>;\n    protected invoke(call: RemoteCall): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    restCall(call: RestCall): Promise<RestResult>;\n    remoteCall(call: RemoteCall): Promise<any>;\n    eventCall(call: EventCall): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    restSecret: string;\n    restTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly restSecret: string;\n    public readonly restTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    restAuth(call: RestCall, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(call: RemoteCall, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(call: EventCall, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public restAuth(call: RestCall, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(call: RemoteCall, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(call: EventCall, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, call: RestCall): Promise<RestResult>;\n    protected abstract setup(app: Express, ctx: Context, call: RestCall): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.24","_npmVersion":"6.0.1","_nodeVersion":"9.11.1","_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"dist":{"integrity":"sha512-QZhZJKis0QMtVsveRjr35iwSP0c+fN0g+2rK8hdBgqxlriomFI8SuIzrDMkXvkMQHEwzMwBWDz5SEkaSpEfbDQ==","shasum":"a7ab64dafe939191bfdaa924abd97ec5a34f8aed","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.24.tgz","fileCount":218,"unpackedSize":556920,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJa9v1kCRA9TVsSAnZWagAAaqkP/3xET7P4TdHf+exWA1Pb\n2HujUEYqFg5l2MfrXR8dChoQebEpbACiUhZjR5Kg6n4MJViHy9wrOOJrSPNb\nx+YAT8EL4HULFuiP494i5aJDpjk/NBLeeocCtK0PX7dmNJNZarexm4tUEzdt\nQnBGUZs0RH086/Acao0hveXkW/FI+WBvDiru8Ich+t8IyXeeVJR/Ua6Vm0ZM\neeB4QFuVVGgaNDP1Y+sebFS6jcXTvrV6bf6YcODWVqjdA8Qd6r2UXBvamfWn\nNjVuueuSU1kUCY2JXGgASqqU51GSq+m7kcenpwBFY6CTWKuPVpK7zGv/SFGP\ntYZZybojzciCHyr6ZBzwGRzsjGxIMlXxr82EV++QoqVCQ7cg6SjjyFAcklr9\nvG2xqiR4VI3Q4Z2PV8e/y3+qwHjsCAMDlGn/TMhTDiPsRfL01UVy67gP6OQn\nNhkdzEpLP7XQoS6Z2MYSLS1uZ9qRrvFm21/EsmztwsjPyZI+98JbQhoD9FCG\nkYxCzGpwcCc5/jjidPDMcJcWgvsqsB2gR57ECMOBxOTCNJH4hvuD7rHRnHqt\nsMO3/i5HOeNw41RZsVIM94YkRi3h7lpaJ1pkJL4Oj0z/tLPJr6Nw1cY3I0MS\nPDGyAE6igJf+/xLyxSkwZTCVz6s3RK616DmHx8Aw+PY8yzPlrIMivj7isRt8\nfgD7\r\n=20jd\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCmFb+lgIYcEA1Oa2NoKtKvOwLN89C4koriTTs01T7v4QIgYCnnqPZTrxxSfC80Yx2omS1U7OA9u9NHipCnSgtZHf4="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.24_1526136163930_0.8595940649713494"},"_hasShrinkwrap":false},"0.1.25":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.25","private":false,"license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"main":"index.js","typings":"index.d.ts","typescript":{"definition":"index.d.ts"},"scripts":{"build":"npx typescript"},"dependencies":{"aws-serverless-express":"^3.2.0","body-parser":"^1.17.2","express":"^4.16.3","jsonwebtoken":"^7.4.3","ms":"^2.1.1","reflect-metadata":"^0.1.12","typeorm":"^0.2.5","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/del":"^3.0.1","@types/express":"^4.11.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/jsonwebtoken":"^7.2.7","@types/merge-stream":"^1.1.0","@types/ms":"^0.7.30","@types/node":"^9.6.15","@types/uuid":"^2.0.30","aws-sdk":"^2.238.1","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","ts-node":"^3.3.0","typescript":"^2.8.3"},"readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Call Object](#41-call-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP/REST Decorators](#6-httprest-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. RestAdapter function](#67-restadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @CallObject decorator](#710-callobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external calls. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function calls within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function calls are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote calls from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote call via `LambdaProxy`. The call is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote call is being prepared the secret for the target application is being used; when a remote a call is received the secret corresponding to the calling application is used to authorize the call.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all calls to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `REST_SECRET` that is used to sign and verify the web tokens as well as `REST_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REST_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    REST_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, call: RestCall): Promise<RestResult>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, call: RestCall): Promise<RestResult>;\n    onPost(ctx: Context, call: RestCall): Promise<RestResult>;\n    other(ctx: Context, call: RestCall): Promise<RestResult>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, call: RestCall): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    protected setup(app: Express, ctx: Context, call: RestCall): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.post(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.put(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.delete(\"/app/:id\", (req, res) => this.flush(req, res, ctx, call));\n    }\n\n    private flush(req: Request, res: Response, ctx: Context, call: RestCall) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: req.path,\n            method: req.method,\n            headers: req.headers,\n            params: req.params,\n            query: req.query,\n            body: req.body,\n            lambda: { ctx, call }\n        };\n        res.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Call object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Call object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Call object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Call Object and the Context Object\n\n### 4.1. Call Object\n\nThe `RestCall` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Call {\n    type: \"remote\" | \"internal\" | \"rest\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface RestCall extends Call {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: RestContentType;\n}\n\ninterface RestHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface RestContentType extends RestHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"rest\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP/REST Decorators\n\nHTTP/REST decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: RestAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `RAW` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface RestResult {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `RestAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and call objects to method arguments. When a `RestAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface RestAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        call?: RestCall,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `RestAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, call, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    call.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@CallObject` decorator\n\nTo inject directly the Call object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@CallObject() call: RestCall) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP/REST decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP/REST decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP/REST decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(call: RemoteCall): Promise<string>;\n    protected abstract invoke(call: RemoteCall): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(call: RemoteCall): Promise<string>;\n    protected invoke(call: RemoteCall): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    restCall(call: RestCall): Promise<RestResult>;\n    remoteCall(call: RemoteCall): Promise<any>;\n    eventCall(call: EventCall): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    restSecret: string;\n    restTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly restSecret: string;\n    public readonly restTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    restAuth(call: RestCall, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(call: RemoteCall, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(call: EventCall, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public restAuth(call: RestCall, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(call: RemoteCall, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(call: EventCall, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, call: RestCall): Promise<RestResult>;\n    protected abstract setup(app: Express, ctx: Context, call: RestCall): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.25","_npmVersion":"6.0.1","_nodeVersion":"9.11.1","_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"dist":{"integrity":"sha512-v/x4kMrRpvQGkcrTUGlQ32hPV2D5cUy00y3+lOmCcAPTVOXBwx2r+ZUVQqYM0baTxngU63aEGrEBjXEkKxk1Jg==","shasum":"2320a82e64bceadaf283dfc2bd17ac24ee7cf92d","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.25.tgz","fileCount":218,"unpackedSize":556786,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJa9xz/CRA9TVsSAnZWagAAZ8YP/i4OUUt0VKImC9om3Hbh\nLOxQAcpH0jQEuPsM4Tt4EQVplmttjtQx7bBGaIwq2yiuf9WPskLa8FOmfauN\nQ8FVLGf+sZ/gMnliBzsxbEJHIV35rwB86PraksTuUAED59ij+NYYCudf0yja\n5a3PZ2h67vsGZbjbf5bEzd1kAKgAphW8tL4elIsVKOLq1T3H8f+TrjDkSwAs\nCPRmt4U8bOeFlU9tXTFvdSt6DSlmTvZnw5Fvm8OCa/oUOQCalsJRW/qsqmNy\n7lkiCpnnw69SODn179Bd6bYU2Ns6q4OrFhbfYi7ERETf4wfSZfzqga5pQFzi\n7G0XgoT64UnkKJorelooCSsTUhB+GdhBV79AvK5QkHgB+7dD39DVfxbwd89e\n8j42am9KuiDP+OasLkGzhYtYGdsG1T8TVLVmJwMJmquH3qoS0+hADFz2bZcW\nb2E/2UW9jt/t6LyBRKzj9I4xWb+fsWQpHbV63zPanAaoBykRryV3kZulSixu\niAiNR+ubZhqFhTYBugWTkc/OVoEeNZjtN6DMTf9jAy2r7mIx8AZUiOpwiQkC\nWOzONfQ/zug6JJBuvFhA466cpFUmHgMEAlDS/pfz2DOduW3jR44hnmIn5DK4\nK9YwDM8XxufBMkyzaHwuIdWN+y9oapcXIjsu6YiLn2YCEEm9jt3ggC+C5cun\n0+gq\r\n=f2xI\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAxR5rrF/p5RsXZF4EoDgN46q4mP6cqZjmWVaIIRSYKjAiEAorG7o8oXlFYS9nStn1nXKRrQwTJQYzWosjppGKp1zrg="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.25_1526144254897_0.42533457416608167"},"_hasShrinkwrap":false},"0.1.26":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.26","private":false,"license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"main":"index.js","typings":"index.d.ts","typescript":{"definition":"index.d.ts"},"scripts":{"build":"npx typescript"},"dependencies":{"aws-serverless-express":"^3.2.0","body-parser":"^1.17.2","express":"^4.16.3","jsonwebtoken":"^7.4.3","ms":"^2.1.1","reflect-metadata":"^0.1.12","typeorm":"^0.2.5","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/del":"^3.0.1","@types/express":"^4.11.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/jsonwebtoken":"^7.2.7","@types/merge-stream":"^1.1.0","@types/ms":"^0.7.30","@types/node":"^9.6.15","@types/uuid":"^2.0.30","aws-sdk":"^2.238.1","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","ts-node":"^3.3.0","typescript":"^2.8.3"},"readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Call Object](#41-call-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP/REST Decorators](#6-httprest-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. RestAdapter function](#67-restadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @CallObject decorator](#710-callobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external calls. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function calls within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function calls are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote calls from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote call via `LambdaProxy`. The call is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote call is being prepared the secret for the target application is being used; when a remote a call is received the secret corresponding to the calling application is used to authorize the call.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all calls to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `REST_SECRET` that is used to sign and verify the web tokens as well as `REST_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REST_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    REST_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, call: RestCall): Promise<RestResult>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, call: RestCall): Promise<RestResult>;\n    onPost(ctx: Context, call: RestCall): Promise<RestResult>;\n    other(ctx: Context, call: RestCall): Promise<RestResult>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, call: RestCall): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    protected setup(app: Express, ctx: Context, call: RestCall): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.post(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.put(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.delete(\"/app/:id\", (req, res) => this.flush(req, res, ctx, call));\n    }\n\n    private flush(req: Request, res: Response, ctx: Context, call: RestCall) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: req.path,\n            method: req.method,\n            headers: req.headers,\n            params: req.params,\n            query: req.query,\n            body: req.body,\n            lambda: { ctx, call }\n        };\n        res.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Call object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Call object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Call object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Call Object and the Context Object\n\n### 4.1. Call Object\n\nThe `RestCall` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Call {\n    type: \"remote\" | \"internal\" | \"rest\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface RestCall extends Call {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: RestContentType;\n}\n\ninterface RestHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface RestContentType extends RestHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"rest\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP/REST Decorators\n\nHTTP/REST decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: RestAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `RAW` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface RestResult {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `RestAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and call objects to method arguments. When a `RestAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface RestAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        call?: RestCall,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `RestAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, call, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    call.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@CallObject` decorator\n\nTo inject directly the Call object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@CallObject() call: RestCall) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP/REST decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP/REST decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP/REST decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(call: RemoteCall): Promise<string>;\n    protected abstract invoke(call: RemoteCall): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(call: RemoteCall): Promise<string>;\n    protected invoke(call: RemoteCall): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    restCall(call: RestCall): Promise<RestResult>;\n    remoteCall(call: RemoteCall): Promise<any>;\n    eventCall(call: EventCall): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    restSecret: string;\n    restTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly restSecret: string;\n    public readonly restTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    restAuth(call: RestCall, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(call: RemoteCall, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(call: EventCall, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public restAuth(call: RestCall, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(call: RemoteCall, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(call: EventCall, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, call: RestCall): Promise<RestResult>;\n    protected abstract setup(app: Express, ctx: Context, call: RestCall): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.26","_npmVersion":"6.0.1","_nodeVersion":"9.11.1","_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"dist":{"integrity":"sha512-Eh1tQ6H3ob4s4WilZkBrCpvHb9HZYUj1RqfeOSvBlwzlg9D4sAqINgaTGQyM4UvF62rjLOi5vdARzvhzeyDU6A==","shasum":"cdfbf048d1bc6be583bdcf608c3bb07902f88944","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.26.tgz","fileCount":218,"unpackedSize":556711,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJa9yOkCRA9TVsSAnZWagAAOiEP/2bGNEUbFZMDhNoR3OAi\n/tk31eZJgWo84Ffi650+AJlqRe6FghWoR7TQfO+opwTrNJ+zCZT38FtuZU89\nnTb6NoNtdLHr8tBV+giVdWTwo4jhIK3njxdkJUGjl05MYFoNY5NVO8qVdKPG\n5hYZeuLOU6W+A2hozKDNuFt+8ZVdOMTjL6JFLPf5kTmMkfSVopzEb8J1XE/Z\nEKVXzZx37CvvSJntlQ9q9hguPvS+6DtEL2ztaWHqwTa7o4MjT8eyr/Id671L\nfr3i83IWsf3VZTB8TE3/vXUXaDfnci5kGHdtdn9AyzpjrlQATSvf+48IsAPg\n0vp1XlxE+dyFYAMcOp5Pe0+zxWlGi1jivEuAyzZoisKiXWsvQi67CFvkw9o+\nW4HqdxicqIJA58ACMx8QBy8PZQan/YfFZZX3wu3P4RYLkmwyh92Z61oNR5g4\nYTKc9Xt3nXDbiKb7rhaSrFNU4DY6xPTlGfT0mFNSf3EXsMQZEdwkBkTb6nOA\nn24DU8GeLGBKyZi3I7CkkTCSak4wupXH5D7cMa/ZXPFpv37182eK4hAx3PJS\n+Ql1QiA1+X6JcPUyA1bEjujGGvSkajA3tL8NTihmgm+KahaRxFa+iWcYx3KW\nofOVyipESTyWbkjSE+fhyfEQj2UVfqmBNOYKGbx6Ugz519cVTmt9B53L/v+H\nsPzR\r\n=Ei4q\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCY7Gx/6qqezH/KBt2Fo5D2ypr2R/NOBMSPcm3j6tnm7AIhAKyncjoCeeq3py7+suKkEy049MBkl3GJGDujOcZ861Co"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.26_1526145956156_0.5582768541233281"},"_hasShrinkwrap":false},"0.1.27":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.27","private":false,"license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"main":"index.js","typings":"index.d.ts","typescript":{"definition":"index.d.ts"},"scripts":{"build":"npx typescript"},"dependencies":{"aws-serverless-express":"^3.2.0","body-parser":"^1.17.2","express":"^4.16.3","jsonwebtoken":"^7.4.3","ms":"^2.1.1","reflect-metadata":"^0.1.12","typeorm":"^0.2.5","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/del":"^3.0.1","@types/express":"^4.11.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/jsonwebtoken":"^7.2.7","@types/merge-stream":"^1.1.0","@types/ms":"^0.7.30","@types/node":"^9.6.15","@types/uuid":"^2.0.30","aws-sdk":"^2.238.1","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","ts-node":"^3.3.0","typescript":"^2.8.3"},"readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Call Object](#41-call-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP/REST Decorators](#6-httprest-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. RestAdapter function](#67-restadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @CallObject decorator](#710-callobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external calls. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function calls within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function calls are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote calls from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote call via `LambdaProxy`. The call is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote call is being prepared the secret for the target application is being used; when a remote a call is received the secret corresponding to the calling application is used to authorize the call.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all calls to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `REST_SECRET` that is used to sign and verify the web tokens as well as `REST_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REST_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    REST_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, call: RestCall): Promise<RestResult>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, call: RestCall): Promise<RestResult>;\n    onPost(ctx: Context, call: RestCall): Promise<RestResult>;\n    other(ctx: Context, call: RestCall): Promise<RestResult>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, call: RestCall): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    protected setup(app: Express, ctx: Context, call: RestCall): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.post(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.put(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.delete(\"/app/:id\", (req, res) => this.flush(req, res, ctx, call));\n    }\n\n    private flush(req: Request, res: Response, ctx: Context, call: RestCall) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: req.path,\n            method: req.method,\n            headers: req.headers,\n            params: req.params,\n            query: req.query,\n            body: req.body,\n            lambda: { ctx, call }\n        };\n        res.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Call object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Call object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Call object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Call Object and the Context Object\n\n### 4.1. Call Object\n\nThe `RestCall` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Call {\n    type: \"remote\" | \"internal\" | \"rest\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface RestCall extends Call {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: RestContentType;\n}\n\ninterface RestHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface RestContentType extends RestHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"rest\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP/REST Decorators\n\nHTTP/REST decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: RestAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `RAW` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface RestResult {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `RestAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and call objects to method arguments. When a `RestAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface RestAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        call?: RestCall,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `RestAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, call, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    call.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@CallObject` decorator\n\nTo inject directly the Call object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@CallObject() call: RestCall) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP/REST decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP/REST decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP/REST decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(call: RemoteCall): Promise<string>;\n    protected abstract invoke(call: RemoteCall): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(call: RemoteCall): Promise<string>;\n    protected invoke(call: RemoteCall): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    restCall(call: RestCall): Promise<RestResult>;\n    remoteCall(call: RemoteCall): Promise<any>;\n    eventCall(call: EventCall): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    restSecret: string;\n    restTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly restSecret: string;\n    public readonly restTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    restAuth(call: RestCall, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(call: RemoteCall, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(call: EventCall, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public restAuth(call: RestCall, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(call: RemoteCall, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(call: EventCall, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, call: RestCall): Promise<RestResult>;\n    protected abstract setup(app: Express, ctx: Context, call: RestCall): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.27","_npmVersion":"6.0.1","_nodeVersion":"9.11.1","_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"dist":{"integrity":"sha512-coFtHQTOJuuNXQdIwuw1/u/ax14dEK6Ey42dppRhZ1B/jDkCGzZSp5x1mpy8iQkKXkUXB64UKfHuc3aPiKREmg==","shasum":"407c015406353db3299ee811d93a5215d2b4a4e3","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.27.tgz","fileCount":218,"unpackedSize":556762,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJa9ymxCRA9TVsSAnZWagAAWyIP/03dMcXMG6HmLKp2xWFS\nwkb8J/PaEQn94oVN0POw+t3jpyO8xbXP8LYGHMW9OpN1h3i7sACpdGSLBUnn\nKiIuK4EYKr4RI0TinbJN0c4zt0Aq6hcqAaSZr96TkzxNbFZBVQSOlR/nke/D\nD2yKIL2tC6OQ5zDypgv4PsQ2h5ha4j1Ttur5bptHm6y8UR1ekgDSZH3nPqR/\nv6MvxXy4lyOjl5GkY7z03sk9T7igfQjtHOkUtWG/4kYyZV1Lz9IzLO3Q9ylr\nKDBc0CBUPJf3mDAwvvSI2VwkbwtlnZwCv7ixoHliLhGThEAEkcuF3W48Pxp7\nC4iEq0FqL/nWZWZYcoVLZtdl8L7vkSzbSUd+6n1budZCt+mgP6EWJAVei8PD\nJgQugGMA/mGGdggS9JNWUX2hBRzqkVjmlDt2CszJrFawdbFBa/R3fD/aLcQq\nNVFQtkUXhjydaY+7ACI6Ig4+M8wTV3CH2A27oDqjdkPDoWWSI8tFkCBXyD0Z\nmaOrXJ5jJZy/TMphC5cmfRJATZ5XjGUIHuAHJEKoXTtIubMs0SHGT7873CTj\n1gl4hK9rDc9AJhLoY8wTf3yQBJpQn+E9SW/ojAYM9bGsBNTUvqCgd0qBMMgN\n9MmHP25c4kwUUCibMUxTTh1AZUHGf/vkuSbQWNxU73tmrookfL4/Remic0/a\nxwhK\r\n=f4LD\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCBJS+4l7gLs7RI0D7L/iN5t7ZfFqH6ExG5+yNRg1bjIwIhANTRsrsvhgUukctT9xU8x5XcvoF2Y9xr3P0tLDEtXAJI"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.27_1526147505474_0.16498799372068218"},"_hasShrinkwrap":false},"0.1.28":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.28","private":false,"license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"main":"index.js","typings":"index.d.ts","typescript":{"definition":"index.d.ts"},"scripts":{"clean":"rm -rf build/","build":"npx tsc && cp package.json lib/package.json"},"dependencies":{"aws-serverless-express":"^3.2.0","body-parser":"^1.17.2","express":"^4.16.3","jsonwebtoken":"^7.4.3","ms":"^2.1.1","reflect-metadata":"^0.1.12","typeorm":"^0.2.5","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/del":"^3.0.1","@types/express":"^4.11.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/jsonwebtoken":"^7.2.7","@types/merge-stream":"^1.1.0","@types/ms":"^0.7.30","@types/node":"^9.6.15","@types/uuid":"^2.0.30","aws-sdk":"^2.238.1","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","ts-node":"^3.3.0","typescript":"^2.8.3"},"readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Call Object](#41-call-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP/REST Decorators](#6-httprest-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. RestAdapter function](#67-restadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @CallObject decorator](#710-callobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external calls. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function calls within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function calls are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote calls from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote call via `LambdaProxy`. The call is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote call is being prepared the secret for the target application is being used; when a remote a call is received the secret corresponding to the calling application is used to authorize the call.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all calls to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `REST_SECRET` that is used to sign and verify the web tokens as well as `REST_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REST_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    REST_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, call: RestCall): Promise<RestResult>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, call: RestCall): Promise<RestResult>;\n    onPost(ctx: Context, call: RestCall): Promise<RestResult>;\n    other(ctx: Context, call: RestCall): Promise<RestResult>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, call: RestCall): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @CallObject() call: RestCall): Promise<RestResult> {\n        return super.process(ctx, call);\n    }\n\n    protected setup(app: Express, ctx: Context, call: RestCall): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.post(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.put(\"/app\", (req, res) => this.flush(req, res, ctx, call));\n        app.delete(\"/app/:id\", (req, res) => this.flush(req, res, ctx, call));\n    }\n\n    private flush(req: Request, res: Response, ctx: Context, call: RestCall) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: req.path,\n            method: req.method,\n            headers: req.headers,\n            params: req.params,\n            query: req.query,\n            body: req.body,\n            lambda: { ctx, call }\n        };\n        res.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Call object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Call object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Call object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Call Object and the Context Object\n\n### 4.1. Call Object\n\nThe `RestCall` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Call {\n    type: \"remote\" | \"internal\" | \"rest\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface RestCall extends Call {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: RestContentType;\n}\n\ninterface RestHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface RestContentType extends RestHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"rest\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP/REST Decorators\n\nHTTP/REST decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: RestAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: RestAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `RAW` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface RestResult {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `RestAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and call objects to method arguments. When a `RestAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface RestAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        call?: RestCall,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `RestAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, call, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    call.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@CallObject` decorator\n\nTo inject directly the Call object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@CallObject() call: RestCall) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP/REST decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP/REST decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP/REST decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP/REST decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(call: RemoteCall): Promise<string>;\n    protected abstract invoke(call: RemoteCall): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(call: RemoteCall): Promise<string>;\n    protected invoke(call: RemoteCall): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    restCall(call: RestCall): Promise<RestResult>;\n    remoteCall(call: RemoteCall): Promise<any>;\n    eventCall(call: EventCall): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    restSecret: string;\n    restTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly restSecret: string;\n    public readonly restTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    restAuth(call: RestCall, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(call: RemoteCall, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(call: EventCall, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public restAuth(call: RestCall, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(call: RemoteCall, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(call: EventCall, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, call: RestCall): Promise<RestResult>;\n    protected abstract setup(app: Express, ctx: Context, call: RestCall): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.28","_npmVersion":"6.0.1","_nodeVersion":"9.11.1","_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"dist":{"integrity":"sha512-+l33qmVJHArUVUsu2vuB3kgxXhv+yMu34u1D+xOYt1WdbbBhaKlurrCwe6mdiZKB6XcTPHpAqRcYnpXtfG+YrQ==","shasum":"61c60421c8b6fbb26f67208a46b6d2c55c76fc29","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.28.tgz","fileCount":218,"unpackedSize":555111,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJa+zdHCRA9TVsSAnZWagAAdoAP/3GHHAMsODQRezevoRXf\ngTNAck2fCm0jyqVJc7fpYY6KmDzC2s2P0F0v5fGmeodJuk011jDdQ7SfuOsA\niwg6nZOsaHo0Y5r7Mr7hvIjMtgeLuZn4LiqWtEBk9cNYiYYgz/bGKWjDVHtd\nT6E/m6ftesXYhjwoPwdn6VD+WYHP6F2a2HL+qEF1mq1AP+LSH7OTlyVCPOX5\n9zs2mgnZl1HeDm2RyqIzzLmD8LdQm3+eAGciUg4L1xf+lZs0Cna+3ZoQYyyf\nQ7GH0pK2yEgoW+eIEuQgspDcuUcBfeqFXEzF33fHVqALouvx+fcHFHGb4KTY\nbTkO4E/+yRKBnfrle8g3dBq6oukbG6cigSNNoKtQzu8OVyrAKeStULtYicsc\nXqd/TU99xTwv08HkSyO83HLLEgX91kmys5FstzlVXAxHnR7IfA9waH6qCjhb\n22tdVI8VLW+EO5Chzqtok3HJvCHZ+kyY4atTiAPkN2MFU2/s52kdB1a/z/po\nnhaM4aYLzyvDQB2IQLbOnAT4UOi9njmfOHGX6bp8H+2aIhcm9U+fyGRlAuQ8\nUIEPTZw597AI1htDuevZNtaIC6hI2cGEBeu93nTzgOPQI4IlDP/p6+P7ZvhB\njKKXTjQslEsyijLaYZWBFqwZ6fP7xeMVPjTdaZazmSY2UbQERqanbjPZjfD6\nKSnf\r\n=B0lo\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCJg+iDhj+Mag879AEh9+y0AXc8bjQ3webeflZPU/+NjwIgewVJ4Y5w4fjkU5ER7TmRqRVvMq9PsFxceS+Wsql/yuY="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.28_1526413126476_0.03805267274720303"},"_hasShrinkwrap":false},"0.1.29":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.29","private":false,"license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"main":"index.js","typings":"index.d.ts","typescript":{"definition":"index.d.ts"},"scripts":{"clean":"rm -rf build/","build":"npx tsc && cp package.json lib/package.json"},"dependencies":{"aws-serverless-express":"^3.2.0","body-parser":"^1.18.3","express":"^4.16.3","jsonwebtoken":"^8.2.1","ms":"^2.1.1","reflect-metadata":"^0.1.12","typeorm":"^0.2.5","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/del":"^3.0.1","@types/express":"^4.11.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/jsonwebtoken":"^7.2.7","@types/merge-stream":"^1.1.0","@types/ms":"^0.7.30","@types/node":"^9.6.16","@types/uuid":"^2.0.30","aws-sdk":"^2.240.1","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","ts-node":"^3.3.0","typescript":"^2.8.3"},"readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.29","_npmVersion":"6.0.1","_nodeVersion":"9.11.1","_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"dist":{"integrity":"sha512-5htofITqt8EYrgBtieKN30a6iOGv9UmyMLFyhp17ansL0mgomyTwLYKoeeR5dx7DgZzOdcA34Ycsyg8rQTVGRg==","shasum":"95b157e5528d212c4a05d66e465900eb3a1ab8c8","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.29.tgz","fileCount":214,"unpackedSize":550230,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJa+5JqCRA9TVsSAnZWagAABUAP/i0pdXQi4pAR0/sb9Jy+\nztEAW56Ii5Q/7ISyY5NyBSufwdpXMuCkK5w4+bvnZAy91+fw0JmFbsMN7R2A\n2NAZqZ8vc7G/dFlIMz9QiHPbNqlOF82l+e8hQZMkiL/fmyV2Z1ZbF/VRvcxA\ntcVhw11+qQlPlNxVUgcEpsyOI+LViEGixXYECezqDgcDZ4tgOZU8+Dv3g8pZ\ng6DnCJoOjMsDuaLBn6iAXY/NceF1jMW9aooI58WSKG6DgExZ14eo4uun5cAf\nsYutFjwV6aAzA6zfrIL50YrI3HXNs0ACyZ26SpocczOucmXrfSEH0ofc4BBC\nnKfhLTqfqFySjL9l3SFsfi0rL989V5aIWfORSJVTIwnP5y4+NDkKEIf7FYVh\niXPoXZDoeZcqiOfBnMpfuPv/X5L3kAGeJ8eg2+i6+ZplyT6qRjfP+5921DLV\n4fB7+U4nIgybqzPrtvEuSQ+6bsxnEhGgMt1PdMAEcDmgiK0RGU77tAhz6v9X\niAbfCfd4rf2ZkZ2pyicGIKC//LfD2M0AJDwM+LxsOHFUiRgP98ajYp6gJw3c\nRXwVVNYE42yQW79vtZf3SMf6s4p/H7NfsGavz/m7B5olt6Ba46VWdem2bEkn\n3e3a9O8gfat9M6ug+KwA8avFnpxkGl8rFsZBSw7TGlQ9XUGzw6KgW2mBP3rH\njDo3\r\n=dNjA\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFT8DuY0RjuOYDC3WE/1XyIWQYmjxLZEcZHx7UdrZBedAiEAq2W6d5qPNExsnH40AV+q5++06zm0ZwEvq/Hi+aPeLD0="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.29_1526436458149_0.32610341721672764"},"_hasShrinkwrap":false},"0.1.30":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.30","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"main":"index.js","typings":"index.d.ts","typescript":{"definition":"index.d.ts"},"scripts":{"clean":"rm -rf build/","build":"npx tsc && cp package.json lib/package.json"},"dependencies":{"apollo-server-core":"^1.3.6","apollo-server-module-graphiql":"^1.3.4","aws-serverless-express":"^3.2.0","body-parser":"^1.18.3","express":"^4.16.3","graphql":"^0.13.2","graphql-iso-date":"^3.5.0","graphql-playground-html":"^1.5.6","graphql-tools":"^3.0.1","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.2.1","ms":"^2.1.1","reflect-metadata":"^0.1.12","typeorm":"^0.2.5","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/del":"^3.0.1","@types/express":"^4.11.1","@types/graphql":"^0.13.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/jsonwebtoken":"^7.2.7","@types/merge-stream":"^1.1.0","@types/ms":"^0.7.30","@types/node":"^9.6.16","@types/uuid":"^2.0.30","aws-sdk":"^2.240.1","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","ts-node":"^3.3.0","typescript":"^2.8.3"},"readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.30","_npmVersion":"6.0.1","_nodeVersion":"9.11.1","_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"dist":{"integrity":"sha512-YeSDteMXxSeabWVSyEqpTCjgO6frNBXqJnjdP3UJs0Q7X2Te+xQzojvf5NRIbRsIC7bpni00uUKZ4RcJZqW5ug==","shasum":"f42b204416449ea806dad161acf76564960cba73","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.30.tgz","fileCount":234,"unpackedSize":675181,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJa/FK1CRA9TVsSAnZWagAAWLIQAIRf9GLbz3m0OVUFgbGL\nYeKT26xoK6LRstLl4AHjT/l4dOd4NgoyKnDWLTzVx8ff1gocBLoGlMrGX+zp\nlbHGi3IQRrDpyByyYyaK90aMVQc3rQXTtu3JWXFVtEhJIGt21nHi0Jr1gjKG\nv28t4lm+cLZ4Bhsyq9c3nKUpGjqIfC/SuSMnVp1fG0epVAPEA07+S0mwxTz2\nvbTaUIN4s+neWjBlxdUbVCpM9hCFLaRHp1Tb1Fok6ZPgbg5ycyTDN+v+ypyo\nRGCHEX2HclcOJyt8geXznacbNG8FGRhD12NRLfsouD5SY59a3tWYjTJkyRtQ\nUyHg7IQNymH/l3ke70Ke+UpvLCjBAZCq+VgD5VIVRVXeX1jYQqCSKyiNuiBX\nKQsuV0lC8KKqVfXPSFggYhes2XAY+40hf1y/nRb+vuCCMgCWVlU+TAuS34kk\nNUfypU/Ik6gOvqlCrWEM1jHM571aEWoW71NtYmc9vVXiX2IpUw+LfdmNesxi\nRxQF9aS74lftPqOuVXnUPfhx1rcrZ11K0KBe1PvKIk5FPQfAXsmUb39cHw4L\nTrOPoNc1Us7VykCRSOv+3fZ6pzWI8YRk6cZ12XnnIMXigZwFNBliJ7ixOc3l\nqEzM/4n91Up48me898jLXORAuVNbPBrCD9xXQhDiUNJj7KtMiH8xpKf7OXl+\n7/Wm\r\n=K1Jn\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAnckqxZp5Jg3YkHt5WqARR4LLkbblCg657FLRmle1vfAiBYpKjbmyrRJ+OPpzAo2mMOMlog195KKjHJbz2yu/2sMw=="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.30_1526485685128_0.8333775402794568"},"_hasShrinkwrap":false},"0.1.31":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.31","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"main":"index.js","typings":"index.d.ts","typescript":{"definition":"index.d.ts"},"scripts":{"clean":"rm -rf build/","build":"rm -rf lib ; mkdir lib ; cp package.json lib/package.json ; npx tsc","watch":"rm -rf lib ; mkdir lib ; cp package.json lib/package.json ; npx tsc --watch"},"dependencies":{"apollo-server-core":"^1.3.6","apollo-server-module-graphiql":"^1.3.4","aws-serverless-express":"^3.2.0","body-parser":"^1.18.3","express":"^4.16.3","graphql":"^0.13.2","graphql-iso-date":"^3.5.0","graphql-playground-html":"^1.5.6","graphql-tools":"^3.0.1","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.2.1","ms":"^2.1.1","reflect-metadata":"^0.1.12","typeorm":"^0.2.5","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/del":"^3.0.1","@types/express":"^4.11.1","@types/graphql":"^0.13.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/jsonwebtoken":"^7.2.7","@types/merge-stream":"^1.1.0","@types/ms":"^0.7.30","@types/node":"^9.6.16","@types/uuid":"^2.0.30","aws-sdk":"^2.240.1","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","ts-node":"^3.3.0","typescript":"^2.8.3"},"readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.31","_npmVersion":"6.0.1","_nodeVersion":"9.11.1","_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"dist":{"integrity":"sha512-+BmIcz0FxAsA3QOMCImBYTA6co/wYgSRCvvtBRX4WG6D4sIXmnIufEx+4OJ8uqEWyeCCpNvHHRmaEpjDqUnUFw==","shasum":"f397bd9bf101c47b10f844abd394bceff0cac228","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.31.tgz","fileCount":246,"unpackedSize":750399,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbAZqxCRA9TVsSAnZWagAA1n4P/3hb8dE1X/t9fLlM+oNC\nF+ekT0tMV9gg+AfMjmIKVnpSrQqjVcP1jkOmZzulCtld1d5IQkwtlKe8/ZgM\n3eWh4vGrFjb+iD8VNR2oImbQEGR3/DKjUzpbX5ImpBsn/yB/f0rv9lwnYUaJ\nBygkpO0tY8ad9/ckTfkk6CpBeFGlTB9qcHraH+Y1I9POQWi1XzU2nzQh7u+B\nbYhLNhR0sKEnlFCkUGRSXL1toT7mVPBhHCj4md+giufXOyxAjvYTyaao6AM6\nKrOYPtU0KYLkGWV6UAnsVaD+RIr/Cv5usvYWtpdI1+QO7Qo7CVaMdROPryJY\n8EJqQgZ6Hsbp75Iw+/haa9GLQFcl5T71V85DhcfEj8LvQD7cdAPP0xJ3cs3s\n7VxDOwjZE1IvZYtkeKzGAzwtnMYY9CLlEiJA4KlK71XkN4IEAjecMHkUBEEy\nQfbZXcV4z51S6csNwIrqgIPUoRXTgjCaEau1ELuxgkm0gn4ADaudt/Zk4Iqs\nyFXaBOLwGD7zF/8FajwoTXwBunTs1wEDrir3H1mDLJd1vc0mSRUtdZKmaUCs\nWPET+Dkbc31JUdshZGICb6nM9zw/dpOQiGFn+dqX/crfxwMr+P5yMzdLqJFK\nybepxv06edXw5Sv5LWgrEd8g//wpsMg5+cJwAUmmf4Taz+T//mhZHsjdMvcN\nLYwL\r\n=tnMR\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCbBcxDVJe0AzUbSO6Wd/Ld3qe8yaf3iKHyguTJAkL6NgIgMs6E21CATFXMFOLUurAcJNl19K5Sz+4VxyZ1d4ns90U="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.31_1526831793186_0.5946205277706529"},"_hasShrinkwrap":false},"0.1.32":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.32","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"main":"index.js","typings":"index.d.ts","typescript":{"definition":"index.d.ts"},"scripts":{"clean":"rm -rf build/","build":"rm -rf lib ; mkdir lib ; cp package.json lib/package.json ; npx tsc","watch":"rm -rf lib ; mkdir lib ; cp package.json lib/package.json ; npx tsc --watch"},"dependencies":{"apollo-server-core":"^1.3.6","apollo-server-module-graphiql":"^1.3.4","aws-serverless-express":"^3.2.0","body-parser":"^1.18.3","express":"^4.16.3","graphql":"^0.13.2","graphql-iso-date":"^3.5.0","graphql-playground-html":"^1.5.6","graphql-tools":"^3.0.1","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.2.1","ms":"^2.1.1","reflect-metadata":"^0.1.12","typeorm":"^0.2.5","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/del":"^3.0.1","@types/express":"^4.11.1","@types/graphql":"^0.13.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/jsonwebtoken":"^7.2.7","@types/merge-stream":"^1.1.0","@types/ms":"^0.7.30","@types/node":"^9.6.16","@types/uuid":"^2.0.30","aws-sdk":"^2.240.1","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","ts-node":"^3.3.0","tslint":"^5.10.0","typescript":"^2.8.3"},"readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.32","_npmVersion":"6.0.1","_nodeVersion":"9.11.1","_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"dist":{"integrity":"sha512-DoeG9gQNCITm44hsYSrpGIa+clKCvScDfaOayjnTBHw+/Dz4nowXp5hCIgFJvH60N1+/mZV1Ii2Tx4GXKSFpZA==","shasum":"6d7b477083aff0cbeab5a328b320b6e63e7459b9","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.32.tgz","fileCount":246,"unpackedSize":763207,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbA1V2CRA9TVsSAnZWagAAz5UP/1NDNOXfnn0hKwi0+Xv3\nEOhxQK8vsi0Cltl5s5o5goASWVTKFX/5f9iK2o9U4nR63UazD8q9wBxi7Ye7\nyS2qhw6lm4j6ErYPqdrdBNMPUoBc6w3Rp74oM8J/+4WN9lcaE8LS5nQJebUz\nIUVDPYK4SuTl8twrzWk/kITa0oWLoLRs9QNQUMJLfn5IXCzZqxzYIk5qwoSU\nWy3pRZxaHqQoWQ818UY4ktix54tPoQGeJTRkvbTUvhrYAosHHDKUMxQxz/qR\nmWTjvKvQeEmv+ShFWb0JR1uNRd2IvKZBibtzAyJWplzaWOVPZIDF0KHrA4xo\nrJWvTlIorrIYP9sYz3HPgptOBWUBB2IqBs/TuJdXs7SLTd72SdGqXPUIeAnv\nKXnQFfOX2A1yYkSrop0XBexELps78jiBnzBQUVZOpqEwipiRIKBmHpv3gWd/\nP8wG+loWnfuc+VV3SfrZS7IgtvnNi6GeMdcaPEmmiSZT6CE//RKnrw1CjMvc\nprZmzPASfyBDn3v1iLWWpeoy1Qgx1W7puHw5NPx5otco9aBWb/fP/Pkh0Hyk\nZ2gosyclTaCHJ9biq12zSzxuJBJoO6BUQO68xCLqnDp42G0xrKKQ9Zv+D987\nSZUsF/6SjISPpd7+j0pL6WbxggI7N53cp6NjvtbYJQk6t8VB7CJhvrvTVAlc\nphAC\r\n=N46Q\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCAiwq4H1QVzBOF+bAIfuX1FR9yUacXpAUO80hN+e/gbwIgQnTcy3DIlZ9J8vjqfYGISnRO++e4rlAN5pmDcbnfiJM="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.32_1526945142444_0.44978505683758163"},"_hasShrinkwrap":false},"0.1.33":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.33","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"main":"lib/index.js","typings":"lib/index.d.ts","typescript":{"definition":"lib/index.d.ts"},"scripts":{"clean":"rm -rf ./lib","build":"rm -rf ./lib ; tsc -p .","watch":"rm -rf ./lib ; tsc -p . --watch","link":"yarn link","global":"yarn global add ts-node typeorm typescript gulp serverless tslint"},"dependencies":{"apollo-server-core":"^1.3.6","apollo-server-module-graphiql":"^1.3.4","aws-serverless-express":"^3.2.0","body-parser":"^1.18.3","express":"^4.16.3","graphql":"^0.13.2","graphql-iso-date":"^3.5.0","graphql-playground-html":"^1.5.6","graphql-tag":"^2.9.2","graphql-tools":"^3.0.2","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.2.1","ms":"^2.1.1","reflect-metadata":"^0.1.12","typeorm":"^0.2.5","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/express":"^4.11.1","@types/graphql":"^0.13.1","@types/jsonwebtoken":"^7.2.7","@types/ms":"^0.7.30","@types/node":"^9.6.18","@types/uuid":"^3.4.3","aws-sdk":"^2.245.1","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","shortid":"^2.2.8","ts-node":"^3.3.0","tslint":"^5.10.0","typescript":"^2.8.3"},"globalDependencies":{"@types/del":"^3.0.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/merge-stream":"^1.1.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2"},"gitHead":"33a9885588868b1631524733c6d38181ad206f73","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.33","_npmVersion":"5.6.0","_nodeVersion":"10.1.0","_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"dist":{"integrity":"sha512-lV3Vvsf0Qr57E6s2nQ0dsrPT/qDoQ8Jaw6ht+VpkkB9nJqFpqMY9+sPel/y+YrAQ0cpGxGFsk3fjcaMP5gF7Fg==","shasum":"7b61f23d92c1f1f0b961470a626e13c7eb6c763f","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.33.tgz","fileCount":277,"unpackedSize":692185,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbBm9PCRA9TVsSAnZWagAAHL4QAJvHwQ20pJE+VGVzwzoH\nWy5HWmGSxg8mEu3rjYAJdzl+3t4F/tisUWI/5HIz9K7+aQs17Ul8KLvticuP\nJUZtAY4CmRs20cDENVEUCOe363Jm5gAElm8qTNHUEeDNiOsP2Tfr6BnmnNAr\ni5IoI4cJOSWPBu5ypX8qaTzCc/ixohYyX4rHzGaVe5b10K2tuU8z+Dmn3NHw\nNsOmokbO8GZWWL/qIORzNefuh4gQCpKcKzCN3b98RCIZRxg3SGjYkUTibEdb\nib9H4bQPKZctDmbA6kzVIXyTv/4LSXvEJJpTGEcHUuDGQsxP4TIYZLOVUVJV\nTmghAuJm92HMuWKC5wqpTEbv4T0e0fhzpxQTjJFqfh17L6s1NklTZh4T1utC\ndSE2Rrwse3GNu3cIBNWPMp9QXZyUXGJbax1ndOiaOHZc7nThztibyihwOrid\nVTh27zjDOFGtbujj4yVUQyaW24dgQBmQD+VG+/lRpd8CO2hOlyZz8Dh4Z/Bl\nyEnZ5XHQgPDnmQFf68ic2p5CMxVUw4sZSWRollSqv4lgadUeDktB1yIM4dmm\nkUmu0ip+4QthjjXPjH6Ook3n8KNOOlCyu5RpidXm5s4+zNSO20E+tev1C6Lf\n1tUSTrIemVjbWSD8ENSaKk2HTtA1VQAfVvo5/WFdm8PDYnJ5eadfxHO5v9Lx\nxGiv\r\n=KgXh\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAh6tO6hjR7WfvIeqbQPyoqVd4XWl+rc+qrA+kcSmUtZAiEA5yTJeArAIEaZfWfAcbShut3ALrqex6WYex1hw/OXMHw="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.33_1527148367374_0.5704320542846981"},"_hasShrinkwrap":false},"0.1.34":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.34","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"main":"lib/index.js","source":"src/index.ts","typings":"lib/index.d.ts","typescript":{"definition":"lib/index.d.ts"},"scripts":{"clean":"rm -rf ./lib","build":"rm -rf ./lib ; npx tsc -p .","watch":"rm -rf ./lib ; npx tsc -p . --watch","link":"npm link","global":"npm install -g ts-node typeorm typescript gulp serverless tslint","prepublish":"rm -rf ./lib ; npx tsc -p ."},"bin":{"tyxorm":"./lib/orm/cli.js"},"dependencies":{"apollo-server-core":"^1.3.6","apollo-server-module-graphiql":"^1.3.4","aws-serverless-express":"^3.2.0","body-parser":"^1.18.3","express":"^4.16.3","graphql":"^0.13.2","graphql-iso-date":"^3.5.0","graphql-playground-html":"^1.5.6","graphql-tag":"^2.9.2","graphql-tools":"^3.0.2","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.2.1","ms":"^2.1.1","reflect-metadata":"^0.1.12","uuid":"^3.2.1","app-root-path":"^2.0.1","buffer":"^5.1.0","chalk":"^2.3.2","cli-highlight":"^1.2.3","debug":"^3.1.0","dotenv":"^5.0.1","glob":"^7.1.2","js-yaml":"^3.11.0","mkdirp":"^0.5.1","xml2js":"^0.4.17","yargonaut":"^1.1.2","yargs":"^11.1.0"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/express":"^4.11.1","@types/graphql":"^0.13.1","@types/jsonwebtoken":"^7.2.7","@types/ms":"^0.7.30","@types/node":"^9.6.18","@types/uuid":"^3.4.3","aws-sdk":"^2.245.1","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","shortid":"^2.2.8","ts-node":"^3.3.0","tslint":"^5.10.0","typescript":"^2.8.3"},"globalDependencies":{"@types/del":"^3.0.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/merge-stream":"^1.1.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2"},"gitHead":"5c6e30816dcd5e0d01e557f1bb6117a22981a01b","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.34","_npmVersion":"6.1.0","_nodeVersion":"10.3.0","_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"dist":{"integrity":"sha512-TiLqtY0BUKS3wS4IKFDeMFl+JwSvEQm9ml0HT7cxr12CwNWy64+sdlmWUk6yAMxFoqNekZOCXqmJE7IKXCdGHQ==","shasum":"0cd87f3110eb3cfa6364f6cf025fbcc7278549a0","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.34.tgz","fileCount":1830,"unpackedSize":6395136,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbEF9wCRA9TVsSAnZWagAAvgYP/i9jrThtKNOy6C7iSurj\nPEhfTbU9VOmTORA5XwfLIlqopICcz0wmUlYxSik1kKT+TSV1W/45J1yTpOEX\nJe1CCxZ/+EMZf0JkJsFHrNK6okFYWr9VIk98SMaMcKBSLH60p0xpYttD7iuh\niYREacmZFfbjDfrOTeFXB1PEbR+SM7EVc01fpD+96E96ByoPjLicKsX3dAru\n04uIke71MTga96zkZ0XwKd8eQPDQPS33pukX9rAqxJS9+FRrVMssKm7vROpR\nCc/SNEzxr6dS/gx0suVeJPKk1O9fdCDA3bB4L+NcFVCdW9aQNSg41RwuZO73\nRYZIavIM1tL27VbDJAL/05LgR7KcnzbLS49UDczjPYDivm63aO6606O9SLRh\ngZvcJAdPApT2a/ZnG1S5RVdQ+QiZ7WrYmxpc0Bu7eKcj0JN0MyK7/a9MO3hG\njwML5XUfETNbsudL1GAZlQuXAhJin3BCLwlvePJrnpnwHQXOaaHiAhoewfck\nV9AMVwnNqTKv5andEobLtbZDNZq+NPphf49zDT00suv7/ha/EWt3L4ND87lh\n9lsS9UiF3GWz+a+qTCCDBNMbHXrUQ2/drMab8AHuiqFCTc/WSjsXXgrSMPFd\nB1ft8mtIn1FBBSSseByF48J0KNryKpRLuaviBgCf7xgc8rC6bz4eRqu7c3NV\nDf9O\r\n=cT47\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCF9GgM1O/npp/miD3ZZEG+7YUetqohPTwCMxkF0/ESJgIhAPE/sOr8v95s+Z4LigW55lPID9fzbEfMxARhwJhrchqr"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.34_1527799663617_0.6928805462243521"},"_hasShrinkwrap":false},"0.1.35":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.35","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"main":"lib/index.js","source":"src/index.ts","typings":"lib/index.d.ts","typescript":{"definition":"lib/index.d.ts"},"scripts":{"clean":"rm -rf ./lib","build":"rm -rf ./lib ; npx tsc -p .","watch":"rm -rf ./lib ; npx tsc -p . --watch","link":"npm link","global":"npm install -g ts-node typeorm typescript gulp serverless tslint"},"bin":{"tyxorm":"./lib/orm/cli.js"},"dependencies":{"apollo-server-core":"^1.3.6","apollo-server-module-graphiql":"^1.3.4","app-root-path":"^2.0.1","aws-serverless-express":"^3.2.0","body-parser":"^1.18.3","buffer":"^5.1.0","chalk":"^2.3.2","cli-highlight":"^1.2.3","debug":"^3.1.0","dotenv":"^5.0.1","express":"^4.16.3","glob":"^7.1.2","graphql":"^0.13.2","graphql-iso-date":"^3.5.0","graphql-playground-html":"^1.6.0","graphql-tag":"^2.9.2","graphql-tools":"^3.0.2","graphql-type-json":"^0.2.1","js-yaml":"^3.11.0","jsonwebtoken":"^8.2.2","mkdirp":"^0.5.1","ms":"^2.1.1","reflect-metadata":"^0.1.12","uuid":"^3.2.1","xml2js":"^0.4.17","yargonaut":"^1.1.2","yargs":"^11.1.0"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/express":"^4.11.1","@types/graphql":"^0.13.1","@types/jsonwebtoken":"^7.2.7","@types/ms":"^0.7.30","@types/node":"^9.6.20","@types/uuid":"^3.4.3","aws-sdk":"^2.249.1","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","shortid":"^2.2.8","ts-node":"^3.3.0","tslint":"^5.10.0","typescript":"^2.9.1"},"globalDependencies":{"@types/del":"^3.0.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/merge-stream":"^1.1.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2"},"gitHead":"5c6e30816dcd5e0d01e557f1bb6117a22981a01b","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.35","_npmVersion":"6.1.0","_nodeVersion":"10.3.0","_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"dist":{"integrity":"sha512-5ZnY3JRfIEn0eGXiQGD05CMYFmiyTPpviWs4d7YU8iCkulzSFfpCfWjCrEGtG82uVB4/DW8s/l9kmDi1mzrVew==","shasum":"5a218128ddd4a25b8a66ab8336849f783c5519e1","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.35.tgz","fileCount":1830,"unpackedSize":6394952,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbEGIaCRA9TVsSAnZWagAA49kQAI0db5WZA5+4OWrxT8Uh\nU/jMVxr1/ZKuO+YDY9XmhC3Tj2N/iQz6r0cdxmwBi67E6buoX0QGKp4E70y9\nhsjLpAyuX2tHVcbxPMJ2ywkDeufKuuMJwytbnB3FOyyRWs9SyCstxTfzRU5D\nPTAWBouWK/88SbO5/8sYTd5dNXOSjAAdBa9fqvY2uRRRdGVywXNsiHVPv/F7\nDHfvH4XbYgjIEGl8Et5ZRVb9LUOGJXtsUDynNsAOQGM61qVbeOnsNVJAK86n\nPDaZhBo0a7aPhRP9ngVg/Q7vmUuLigeCUoK57za4ThHZBIsVhRmjIEbgbDsO\nYayG6Zyz45Zd+/77H2tS9ZYLGQrA3whtJd6x1PP/Epx2N8TQj+ZUHO4n6JFd\nl6qvSmp8poPdsCZEyssuupjg93v1EcRpauKOuyG9vNHAz63r90vocwpKTes7\nlNOc6PUCwNgcNKc3yQ1+9bLEEatuD88gUXDLFONh/wd9A8JaskV8oToQD07h\n7jvh0baDIlNJKfIz31TNIOk/rYhWa+UJ2dPLSEhgM5/lwU9W25KtUcByJ/S3\nvPhGCp1n3AM0TXIpk+Sy9lOZLsJnRhbyv0VdLbhgOFdUEfO/M2E8yZTe2tQO\nYQAoLN3h1FBdZ6zEO81abXOQebHZxoSa8tzvLUf2V/Id4q+FUbU/IBYCdhoz\niIIx\r\n=l9sY\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBh/wXNDc91hgtucDTKW4uSFt6OkUxSgmCErhhy1zgMgAiEAnpI/BjSdZ4hVlIKBfsPj+QWsPHn8gCK+jpS9WF6ZrGI="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.35_1527800346270_0.7768622416649615"},"_hasShrinkwrap":false},"0.1.36":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.36","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"main":"lib/index.js","source":"src/index.ts","typings":"lib/index.d.ts","typescript":{"definition":"lib/index.d.ts"},"scripts":{"clean":"rm -rf ./lib","build":"rm -rf ./lib ; npx tsc -p .","watch":"rm -rf ./lib ; npx tsc -p . --watch","link":"npm link","global":"npm install -g ts-node typeorm typescript gulp serverless tslint"},"bin":{"tyxorm":"./lib/orm/cli.js"},"dependencies":{"apollo-server-core":"^1.3.6","apollo-server-module-graphiql":"^1.3.4","app-root-path":"^2.0.1","aws-serverless-express":"^3.2.0","body-parser":"^1.18.3","buffer":"^5.1.0","chalk":"^2.3.2","cli-highlight":"^1.2.3","debug":"^3.1.0","dotenv":"^5.0.1","express":"^4.16.3","glob":"^7.1.2","graphql":"^0.13.2","graphql-iso-date":"^3.5.0","graphql-playground-html":"^1.6.0","graphql-tag":"^2.9.2","graphql-tools":"^3.0.2","graphql-type-json":"^0.2.1","js-yaml":"^3.11.0","jsonwebtoken":"^8.2.2","mkdirp":"^0.5.1","ms":"^2.1.1","reflect-metadata":"^0.1.12","uuid":"^3.2.1","xml2js":"^0.4.17","yargonaut":"^1.1.2","yargs":"^11.1.0"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/express":"^4.11.1","@types/graphql":"^0.13.1","@types/jsonwebtoken":"^7.2.7","@types/ms":"^0.7.30","@types/node":"^9.6.20","@types/uuid":"^3.4.3","aws-sdk":"^2.249.1","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","shortid":"^2.2.8","ts-node":"^3.3.0","tslint":"^5.10.0","typescript":"^2.9.1"},"globalDependencies":{"@types/del":"^3.0.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/merge-stream":"^1.1.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2"},"gitHead":"34e11ae9488e8b74594fbe3dfc1fa9748fc39d16","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.36","_npmVersion":"6.1.0","_nodeVersion":"10.3.0","_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"dist":{"integrity":"sha512-1Ub9eiU9UjvCVomKdz2cLVHlpMAe7OINbqGLvLFXiz7NISqE8Tgm3oypF/XU2NchQDVjWEW+Gwni9B5+EZSndQ==","shasum":"1af0edcd1b4f2f9387147c47137460f5403267b3","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.36.tgz","fileCount":1830,"unpackedSize":6395857,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbEHX6CRA9TVsSAnZWagAACvQP/1uTTiCsiWor1n1TZ3s2\nKsWPYVE93fACwjJP1BKG3D9fCUZVDU0ABW8TKqfQknGvyqMuYGMYV3vO9yyV\nyBZytj/HAkRCBO+3XHUa/xsABDLz9xzX1Kve+bxcpOBmWG5sj49sws2faRi5\nATpRy9D/S0J2jqWAiPp7dkBz5gQNBxUIsG5XqKecymmOxIwvbplsaAQNOGSl\njoh3yBeXOwf7dKwt1xvAPk5uaWZoBEgYnV2wQH1ZAmnk2FmOMdfOpsXGj6S5\nLnhwbf86lGf0KrNlAuxcPOQRVmH3kGleMCOoNXYy2FO2k4xLOwbnJHw0EP2K\npifJl+hB1ujf5GPxGc+0MyMPdRG/w7VCF544yPhZHnEEB3dKy8doZIK1Yy6H\nc2bk91rIdFTQBW4L7JDQm7fgAyuwWhB/EKyO9JXdfZy7mm3aWcxGbo2H/+fp\n12gMX+kM2mwfEFvini3f4XMmhuxX4PoO16CR8XN4cA3LAtJ2l2aLn3UnvveZ\nzBahb/Di4K/v/TDUp6MX76kX3/pc+F8IqdKSa9zXguza2Dk1EPaVm/Vf793u\nvxKMOHlC3o2R46CI6atSwh3zcKF+uMJ9HtathAuDXLyFLnyMW7YFqk73mi37\nzYq3tP0NPRDHc+h0Wiu413MLzUNn+fm7CF5BlL1eY4T+5x6Bkm8Ji0oQb8Qm\nw8g1\r\n=1EsI\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDzLgycRkqoIY4RkFWE5U5HjrET15+HTM+BWjo2wwuOVwIhANMTNB7jdhU7Jj0yk/pgBVpNzaXA6Hs8S7qKyIX9E+hj"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.36_1527805434140_0.10290727076013595"},"_hasShrinkwrap":false},"0.1.37":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.37","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"main":"lib/index.js","source":"src/index.ts","typings":"lib/index.d.ts","typescript":{"definition":"lib/index.d.ts"},"scripts":{"clean":"rm -rf ./lib","build":"rm -rf ./lib ; npx tsc -p .","watch":"rm -rf ./lib ; npx tsc -p . --watch","link":"npm link","global":"npm install -g ts-node typeorm typescript gulp serverless tslint"},"dependencies":{"apollo-server-core":"^1.3.6","apollo-server-module-graphiql":"^1.3.4","aws-serverless-express":"^3.2.0","body-parser":"^1.18.3","express":"^4.16.3","futil-js":"^1.48.0","graphql":"^0.13.2","graphql-iso-date":"^3.5.0","graphql-playground-html":"^1.6.0","graphql-tag":"^2.9.2","graphql-tools":"^3.0.2","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.2.2","lodash":"^4.17.10","ms":"^2.1.1","reflect-metadata":"^0.1.12","super-graphiql-express":"0.0.2","typedi":"^0.7.3","typeorm":"^0.2.7","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.0","@types/graphql":"^0.13.1","@types/jsonwebtoken":"^7.2.7","@types/lodash":"^4.14.109","@types/ms":"^0.7.30","@types/node":"^9.6.20","@types/uuid":"^3.4.3","aws-sdk":"^2.251.1","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","shortid":"^2.2.8","ts-node":"^3.3.0","tslint":"^5.10.0","typescript":"^2.9.1"},"globalDependencies":{"@types/del":"^3.0.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/merge-stream":"^1.1.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2"},"gitHead":"841195ffa9f647b8153ead27e9abcd4e249cecc9","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.37","_npmVersion":"6.1.0","_nodeVersion":"10.3.0","_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"dist":{"integrity":"sha512-HDSC16T2Gbl0DDJ8eai7nelJObwR/F3jrvTAd+HlvtDYpCLmUZzcpjVhP5q3Ap7Ni8BJcRfLWwzzlodLMORq6w==","shasum":"65d3dfa034ee378a939c6177bdff8a2b7130fb60","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.37.tgz","fileCount":333,"unpackedSize":875907,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbF3GmCRA9TVsSAnZWagAA23AP/A7o0sCauJK0KNYF1PSx\nmNJMUn/rv6uM42H1sud305F7k8Sy8iw1y1dR9sdjVl5RiLymKwz2FiPA9rFZ\nXFUGmFsQpDWjC7KFSvafFNP76/7ZltnM5f3zPRup+YU+YwqkxhUbMFjgoBT8\nsOzL7Dp3LW+wtJiVk0x2g3QZe8Z17yaDQeyR2JxU/l9JXGCmKyDGtJ/l6vN7\nAb4hRhihbnH0nMPkymHeWAIigArP6W8hNet7UzVTW0ENSGwgVGWlGGspWu3x\n+DUhonPUZh3wLV5G9HIwjC7gBbYUyMfYl9Im4rNvs2piTgBK5PAmx8UadI1z\nVtt70LO5h4qUo3iFAPx3oSMhD7sDzYrBqixUCufGNu41HiNCAz3y31POJILf\nc4FCDDn2KWrBRIwQ8a9pU7AGlewm2r2zze4ThniolLpzr23WHSpd2d2vm5bX\nYhbbnxqekAHPVV79j0jUcRTgY8MSJUDk2TW3cyOuBE0Xtp210Uw2qBS3Mf8E\nN8yIxVpKTHsm9MK0aXhNj20PEVKGhpqjddWPWpr8u9ldvsLfXhUCOwZDEZ94\nwr+sjSxWDK3DoWIU+2R1nHunJ+V+lH1g4cl2ecU64Bm88cileOvluAXqW8fm\nm3kgGJSW5xAzx1aSYVYUeILRt9ipUKwVPU/vEmzE7vaf8QXmQ5BAP4++uPB2\nZjtq\r\n=K+Nh\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD0FlQ9tqLEWBpaC430vf3NPSJ0UzR4aeJSsFUSmvQN9gIhANifdAa7bowuSAah6ki9cvkD4+S8+9NBtZPT/dZNupHF"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.37_1528263078443_0.22313965661605595"},"_hasShrinkwrap":false},"0.1.38":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.38","license":"MIT","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"main":"lib/index.js","source":"src/index.ts","typings":"lib/index.d.ts","typescript":{"definition":"lib/index.d.ts"},"scripts":{"clean":"rm -rf ./lib","build":"rm -rf ./lib ; npx tsc -p .","watch":"rm -rf ./lib ; npx tsc -p . --watch","link":"npm link","global":"npm install -g ts-node typeorm typescript gulp serverless tslint"},"dependencies":{"apollo-server-core":"^1.3.6","apollo-server-module-graphiql":"^1.3.4","aws-serverless-express":"^3.2.0","body-parser":"^1.18.3","express":"^4.16.3","futil-js":"^1.48.0","graphql":"^0.13.2","graphql-iso-date":"^3.5.0","graphql-playground-html":"^1.6.0","graphql-tag":"^2.9.2","graphql-tools":"^3.0.2","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.2.2","lodash":"^4.17.10","ms":"^2.1.1","reflect-metadata":"^0.1.12","super-graphiql-express":"0.0.2","typedi":"^0.7.3","typeorm":"^0.2.7","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.0","@types/graphql":"^0.13.1","@types/graphql-iso-date":"^3.3.0","@types/graphql-type-json":"^0.1.2","@types/jsonwebtoken":"^7.2.7","@types/lodash":"^4.14.109","@types/ms":"^0.7.30","@types/node":"^9.6.20","@types/uuid":"^3.4.3","aws-sdk":"^2.251.1","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","shortid":"^2.2.8","ts-node":"^3.3.0","tslint":"^5.10.0","typescript":"^2.9.1"},"globalDependencies":{"@types/del":"^3.0.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/merge-stream":"^1.1.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2"},"gitHead":"1e46c38c5cd1e1dc770b4bd5c423d94e87b9f3af","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.38","_npmVersion":"6.1.0","_nodeVersion":"10.3.0","_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"dist":{"integrity":"sha512-ZzzFn7JTQPLeU4/3RXIl8OFHt7n7uNUIPv5KWeDxKB23f2VI8GRucwFd8NWSsO/WWd8Ye4V0RIkaeNI7E9tvKg==","shasum":"b47934f5051a10bc635e7765493977777bede73b","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.38.tgz","fileCount":348,"unpackedSize":911631,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbHPOICRA9TVsSAnZWagAA61AQAJOhE8wiKFgUEmwq3zBo\nZ1QNn1RKWOGE2J17bxFviWg1o5tf8LhkoDzTQmXTctjurP0E+3Wdz7GcK1Nq\nCnH80YjNCUx+ZzozhvcE0DmCDud67Ce7DlRXbwc27XZX6lQPQkQSaLohlL47\n6dxhhygoVudd35OH6oiuyxafujnaBClO/HLjpgdEnqsQa/AznKnYLJRPA9wh\nsdBSO4j2M8koiyy2ropbOm2tnHFjrRM+2kiukUWNqskokhLOz3Fxw+A5Gqyr\nHB9qCQwqNON7Gwp/DjhcV2P6H/ihedHHfeE+eoMKf6NmsiC7Dmt/x+VSDd/P\njFu9uJ2gWErh6gdzIKGFSLdkmA1nmB2QUoaR3+za0soAxFSZ6RISw2KT1J5X\nDr1+gtrohrQnCgo2uN4N/fP8XuCh54eL3nIEMa3Vl/FFg8e5K4fACuvxU4hF\nAkXncYtnA6pIu+QZF31hhuZu1ZPD/LYahtiy/YSgK1QGHtyst1KuH5Q73oon\nR+76Hmn/VkoFTF9xrh3438XzwbnHm+Dkjkg5z53I9q8JlyC5gsqRvWUop1/8\nTTrudw6fZXBmB3y4XHnEbIWJbx3pT14DggFn2rKGv635EQSwtGwPkgsvh5Si\nTifUSSU5YcUilM/Y54B2+fAWQJsTvuTWKDE3bFXD5VZK4eE0kjHyJNs9dOFb\nkJO2\r\n=C/dH\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFJqn4HoLxUK0n7mBEOGpdIjD/aNi9XtIWzls1HXAT/LAiEA7Lx2jdt5Yumsu3KXuAMdVK7iK9MmgXdam3VJeQ3GHiA="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.38_1528624007985_0.3532317466530137"},"_hasShrinkwrap":false},"0.1.40":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.40","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"main":"lib/index.js","source":"src/index.ts","typings":"lib/index.d.ts","typescript":{"definition":"lib/index.d.ts"},"scripts":{"clean":"rm -rf ./lib","build":"rm -rf ./lib ; npx tsc -p .","watch":"rm -rf ./lib ; npx tsc -p . --watch","link":"npm link","global":"npm install -g ts-node typeorm typescript gulp serverless tslint"},"dependencies":{"apollo-server-core":"^1.3.6","apollo-server-module-graphiql":"^1.3.4","aws-serverless-express":"^3.2.0","body-parser":"^1.18.3","express":"^4.16.3","futil-js":"^1.48.0","graphql":"^0.13.2","graphql-iso-date":"^3.5.0","graphql-playground-html":"^1.6.0","graphql-tag":"^2.9.2","graphql-tools":"^3.0.2","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.2.2","lodash":"^4.17.10","ms":"^2.1.1","reflect-metadata":"^0.1.12","super-graphiql-express":"0.0.2","typedi":"^0.7.3","typeorm":"^0.2.7","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.0","@types/graphql":"^0.13.1","@types/graphql-iso-date":"^3.3.0","@types/graphql-type-json":"^0.1.2","@types/jsonwebtoken":"^7.2.7","@types/lodash":"^4.14.109","@types/ms":"^0.7.30","@types/node":"^9.6.20","@types/uuid":"^3.4.3","aws-sdk":"^2.251.1","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","shortid":"^2.2.8","ts-node":"^3.3.0","tslint":"^5.10.0","typescript":"^2.9.1"},"globalDependencies":{"@types/del":"^3.0.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/merge-stream":"^1.1.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2"},"gitHead":"cfe508ae5e61254a33a6d0f0a6450cab2167394d","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.40","_npmVersion":"6.1.0","_nodeVersion":"10.3.0","_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"dist":{"integrity":"sha512-3yQrX4LdVeZmkNIpYIZ0i9XTbR3/LnJ7mJYXe8Q9rxJ9AubGBd+uUO81jsEH6eNSs5EbDSAUb9i5MXJ8EZP+0A==","shasum":"3ac6758047a9f5d799aee7794bb53b56e1114f9a","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.40.tgz","fileCount":348,"unpackedSize":911640,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbHPx1CRA9TVsSAnZWagAAC7oQAIzvWfgQCu1J7AlnvJue\nFPx+hisk3hFH2p8N2rHxgU3qDoGaHfBHb4IVNsC0a6bJEM/Yc0sjtFPv/KRv\nc4QGZPOJFXwzUAQllAgHgndRdderMDhB8y6Riz/GMnJZ9AF+s8P3QT3YrRNz\npZrg7sjB1X7ssL48/1OHESiL/QMllA6wmZe/AeXai95ilDDlXLZxApnDG0c2\nAq5kbmMEKt6DLL/RXUN/Es3f5deFzMkEvVxiEsU+4xCOFjoZtnwZV1d9Nhf3\n9SbOVn33l0rScLQp/YDZKexmkI51P+Hmgxd9XIGBYL0JzMkz04AB8p1mPvdP\n6aaEGWgagCnSdibYZTFDlwOYvmXjUOHEV5pUeY4QYvo3HQlvPWHO2JOpuf14\nQ8jT8h/31ICM41Fo6qRMIRlaitQQctWuHHmKZYJklDlCJLF9AXRwh1z8EVq2\nyvoJ3UTz1vTIW7ChNUeOaG1tFlsMh9ivxmgJWbQiAt7Blp3v2EUvAkmSksov\nc31kaGlXltlRLCx0Vi+k0qAu0miAhjj78Gv43O3K6Yvi+fm6DzsCZ4XZ9o/r\nJOL+DEVw2KX5dvgFBrY68yslKTu28vBUmoR9gVEMOK6CxsgTIxiZIty6GZ9x\nxBKVFOWjPwQhnp/B8+BNYairEYvHALAQl+cdrPTpzpYv9fZiXUBNGYw44sEQ\nnpTE\r\n=pCyQ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHbVA6U6XpJSHdeWvZGNHFAE5mndM7QfzWkIBf8tFYx3AiEAiUmzwjmycXNh1u5ZDySn3or4a805GX2Q9hyGJhJUs3U="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.40_1528626292847_0.3943819744284758"},"_hasShrinkwrap":false},"0.1.41":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.41","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"main":"lib/index.js","source":"src/index.ts","typings":"lib/index.d.ts","typescript":{"definition":"lib/index.d.ts"},"scripts":{"clean":"rm -rf ./lib","build":"rm -rf ./lib ; npx tsc -p .","watch":"rm -rf ./lib ; npx tsc -p . --watch","link":"npm link","global":"npm install -g ts-node typeorm typescript gulp serverless tslint"},"dependencies":{"apollo-server-core":"^1.3.6","apollo-server-module-graphiql":"^1.3.4","aws-serverless-express":"^3.2.0","body-parser":"^1.18.3","express":"^4.16.3","futil-js":"^1.48.0","graphql":"^0.13.2","graphql-iso-date":"^3.5.0","graphql-playground-html":"^1.6.0","graphql-tag":"^2.9.2","graphql-tools":"^3.0.2","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.2.2","lodash":"^4.17.10","ms":"^2.1.1","reflect-metadata":"^0.1.12","super-graphiql-express":"0.0.2","typedi":"^0.7.3","typeorm":"^0.2.7","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.0","@types/graphql":"^0.13.1","@types/graphql-iso-date":"^3.3.0","@types/graphql-type-json":"^0.1.2","@types/jsonwebtoken":"^7.2.7","@types/lodash":"^4.14.109","@types/ms":"^0.7.30","@types/node":"^9.6.20","@types/uuid":"^3.4.3","aws-sdk":"^2.251.1","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","shortid":"^2.2.8","ts-node":"^3.3.0","tslint":"^5.10.0","typescript":"^2.9.1"},"globalDependencies":{"@types/del":"^3.0.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/merge-stream":"^1.1.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2"},"gitHead":"47de98e95f31486b8b8382a937d64d15c82ccb98","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.41","_npmVersion":"6.1.0","_nodeVersion":"10.3.0","_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"dist":{"integrity":"sha512-xyiZ0TMih3P+mJg29YWum9t1i6uG+TJXdNFo+69gydH2hGuX3tT7hUq7orxd+QoMzGJd04RDAFRrK9hGcD3few==","shasum":"e03433f30afbd84f58e9e699f3229318cbe4c275","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.41.tgz","fileCount":348,"unpackedSize":912337,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbHRZxCRA9TVsSAnZWagAA9dMQAKGV6fFaI7YlrYAenrJ5\n7RhAj24bT9JztvZQ6TwUIgPfhpSa7dsfGdknYQmYe5uSWrI6ePWYcKtx9sJE\nGc6m8Wx6slgCYQn3jQ0ft2j6Q/m+HQEtZONYJ7NESW9gSC2QPmmD95koEC05\nYekNBbGLqh0RkSwtIg+GpNcQYoTTsVnK6SGNAnWvTNDnbGJDWOStzOZE/TYS\n1wRitU16CKKXKtgDoEuXHYRBVs6Hh3U3Xr6mdAN54Bjj7QbyP9ljjnWwWHZW\nuLLsCfh+rRAdpo4tXN78rDN/HElT9BP+DrOgrzcuZx+qhBhMAsHozuZdHqjy\nVGogAufX/bf7ecCJ0qJFGq33qf+lPAfxh9G26UiwkHj58TrGb7pN09n0AiXA\nuGJPDoxLLlDA4h536BJZbkwL+ep+p0odMOrQOB0Gd0g4iYyOM9GZr0LN3hcX\nQI6exu5TNxeqfOLEhxYCeOOalb9QRP10BBZIwnny7UrzXPZGKNwGawJjD/T/\nJtFD4t24YrqUukTNoX/tHVZ4GqMe/6boADZJmf+59YfMQSMWeE9/09G4OMHb\nIAttyuV+xkk7KngtUnzn1D3QNnZ06dx7qwoSTweLHPT4RMtLynRM9KvBh0LX\nMVfFEZlTGelRfo3yMy0ez1jlD2KkqjxIykDJALgH0N2di7EqmAFUiJBF4RIp\nd/dv\r\n=r0Y8\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDJ3ignVfBpHqidgM3/m30FTU00LHfx1/Y9yPebPAQ1WAIhAIrhTF4oVEP01uo7NWg0+GIAiTVk3IAC+6hl2xjtUb5T"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.41_1528632945461_0.9330485336759342"},"_hasShrinkwrap":false},"0.1.42":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.42","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"main":"lib/index.js","source":"src/index.ts","typings":"lib/index.d.ts","typescript":{"definition":"lib/index.d.ts"},"scripts":{"clean":"rm -rf ./lib","build":"rm -rf ./lib ; npx tsc -p .","watch":"rm -rf ./lib ; npx tsc -p . --watch","link":"npm link","global":"npm install -g ts-node typeorm typescript gulp serverless tslint"},"dependencies":{"apollo-server-core":"^1.3.6","apollo-server-module-graphiql":"^1.3.4","aws-serverless-express":"^3.2.0","body-parser":"^1.18.3","express":"^4.16.3","futil-js":"^1.48.0","graphql":"^0.13.2","graphql-iso-date":"^3.5.0","graphql-playground-html":"^1.6.0","graphql-tag":"^2.9.2","graphql-tools":"^3.0.2","graphql-type-json":"^0.2.1","graphql-voyager":"1.0.0-rc.15","jsonwebtoken":"^8.2.2","lodash":"^4.17.10","ms":"^2.1.1","reflect-metadata":"^0.1.12","super-graphiql-express":"0.0.2","typedi":"^0.7.3","typeorm":"^0.2.7","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.0","@types/graphql":"^0.13.1","@types/graphql-iso-date":"^3.3.0","@types/graphql-type-json":"^0.1.2","@types/jsonwebtoken":"^7.2.7","@types/lodash":"^4.14.109","@types/ms":"^0.7.30","@types/node":"^9.6.20","@types/uuid":"^3.4.3","aws-sdk":"^2.251.1","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","shortid":"^2.2.8","ts-node":"^3.3.0","tslint":"^5.10.0","typescript":"^2.9.1"},"globalDependencies":{"@types/del":"^3.0.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/merge-stream":"^1.1.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2"},"gitHead":"6dd587910d1512880be499a00dd4eb663d61d47c","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.42","_npmVersion":"6.1.0","_nodeVersion":"10.3.0","_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"dist":{"integrity":"sha512-qYnBTcSgID8PNUmkzJkNuCO3ffZllQf8lt0fHfF0gENZf6aM6G0fzagseY63W7yNJjRj7jPhqtjHdZv4W/Y4tA==","shasum":"da69f86bea7f969f564a9a35114960d4d04da6a6","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.42.tgz","fileCount":352,"unpackedSize":969419,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbHfXeCRA9TVsSAnZWagAAkVIP/3qSsZZ0vDPTGq5/KOfn\n1IMgmIqAaY1M0OFTxdQztfibGIV5dOtho0DR6jv5lRp+FVtSF6pv+jd8yCpH\nrgdfPZcSv+s/LPWwe+kYl7E2xPB1A/WXXHX5Qmz8uqUk7w7vjNhAl+1xH+t1\njO+ZG9SN1hKLoYg5OXwoekO9MMgxdN20ORPz2I6LHg2KZ07XcDqd1mLF7TKR\nYO1ervynIUH+NSVSFZOlFFszSWgXai++cWB0rfRopYoO6+3zZIGKtf9/AHWw\nmXp44Uaz7HeXfAK/VKygrdBMhEnI/ujIJvFJCMtke7ZyFd75UMxmBzaCIpUA\nckRbawoQQI55djw4Jfuy5xVXq66sNv+rcylf3rFaRORlu9pMm+94WuglTsy1\nRQhzuxRFl+MwhVrzJl62kxcndoPpXqF6pZ/L9i2eAk8FCy1mPBa5484DmiCm\ndkpPUKjamGB+TEvBtpFnXZcCujmQW4EkQ2qwOlpZ48/Z6frQ+WLSsMDnBQCL\nzSCrIaXZ+KuzREMdRfRd0U3+iefIH2yVZFHm22DDCV06s8ZldI4oQCc2ekq9\n4nn4/F6nye84vihXJT4gWTFk2ahGv9hHzZvwUDY1cQa84EEsh3+u1a+wE4AX\nNZB99dCmaArrv6dkIDZ8VmsG59dRT3o4QarP7afr79b6oHdR8D1icb8UrcWV\nF4ij\r\n=Rv8/\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDA+b09hlk70bN8ivGttQVv0d3ze8cPKvX744/vWto4iAIhAI7X0G9kwnjll2RiK8FmVMCvqb98YLTTwxWtKh3IcTEB"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.42_1528690141522_0.17279435491273243"},"_hasShrinkwrap":false},"0.1.43":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.43","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"main":"lib/index.js","source":"src/index.ts","typings":"lib/index.d.ts","typescript":{"definition":"lib/index.d.ts"},"scripts":{"clean":"rm -rf ./lib","build":"rm -rf ./lib ; npx tsc -p .","watch":"rm -rf ./lib ; npx tsc -p . --watch","lint":"npx tslint -p .","link":"npm link","global":"npm install -g ts-node typeorm typescript gulp serverless tslint"},"dependencies":{"apollo-server-core":"^1.3.6","apollo-server-module-graphiql":"^1.3.4","aws-serverless-express":"^3.2.0","body-parser":"^1.18.3","express":"^4.16.3","futil-js":"^1.48.0","graphql":"^0.13.2","graphql-iso-date":"^3.5.0","graphql-playground-html":"^1.6.0","graphql-tag":"^2.9.2","graphql-tools":"^3.0.2","graphql-type-json":"^0.2.1","graphql-voyager":"1.0.0-rc.15","jsonwebtoken":"^8.3.0","lodash":"^4.17.10","ms":"^2.1.1","reflect-metadata":"^0.1.12","super-graphiql-express":"0.0.2","typedi":"^0.7.3","typeorm":"^0.2.7","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.0","@types/graphql":"^0.13.1","@types/graphql-iso-date":"^3.3.0","@types/graphql-type-json":"^0.1.2","@types/jsonwebtoken":"^7.2.7","@types/lodash":"^4.14.109","@types/ms":"^0.7.30","@types/node":"^9.6.22","@types/uuid":"^3.4.3","aws-sdk":"^2.259.1","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","shortid":"^2.2.8","ts-node":"^3.3.0","tslint":"^5.10.0","tslint-config-airbnb":"^5.9.2","typescript":"^2.9.2"},"globalDependencies":{"@types/del":"^3.0.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/merge-stream":"^1.1.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2"},"gitHead":"68a26c65fe1a70b89a865055a3fc5f7437d08974","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.43","_npmVersion":"6.1.0","_nodeVersion":"10.4.0","_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"dist":{"integrity":"sha512-4osMOA25YHTwPiV0EodJ1CRRj/ykOb94BFCDX+5+ylTB/dWHW+Ga7LTtOxPcRJTQBRFjJSyMSlmvYVkN0oM/uA==","shasum":"87ac5ffbd826857566675b09df8b073a878be876","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.43.tgz","fileCount":346,"unpackedSize":1000225,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbJkiqCRA9TVsSAnZWagAAhJAP/1GXXSZCx03oWuGoE8pW\nN6Gh+P0K99j/R+CnEAMJaEI+bMObSEuDetMti/yK/IgLUZOka7OP/8HJZ/3w\nfcMgcDqPM4vFzkPt5pSe6pjrdgFgffmmBqVgHrP+jjPNj7nFPBR27YLSQzWJ\nnYkiEQ5ndl75bj4gI0E5ix73XVcgRZLrObC8Jrt2jT7GpYr7LTz45IvStTOt\nXNf7EweIMyvw7cMcPQir4XIEQnN+ww+A3+oORFoXL0vn1So1RZ0BFPrQPycr\nN30GHCMJDtM7Mra8jeSqdaNQU/dT5AbLoFH1g5hbYIq+r4XmaK8o48r5nh2x\nX5Mu8KfDpvYLpjUbLFUg7fDCaxmGVG/6HJnWpqONU//W7koLYLI6udywJfS0\npbx3TjqHIMbyAH7EDps8X0PMSJ4xCuoYyEpSjuf0wsLOnE1gwKdyL6TpKTvI\n+gRHYG2W5ROPNyU3FtmOjmxDUFBlsh+7ABnXbiHtalp6/40KyZwI5t2yWH9r\n9UGQpxHzYt476nD/uZkFgS9Es/lk7Uo8CYMIKvs73APhecWZ4RI4Jvwz11UX\nBohgCGzQ2NmOzeV3a9oFPI14DTjc+lskLEapHA6De3AQ62sQvz/JzMKG7r16\nWbTW815lNZgcJS8G51ChJw8b3m+OnUmWVupBWGYU0ph5t7hPmD9M5ewpL1ay\nsowH\r\n=8SrW\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFuinxrGQC1L9LeX++J3ZaqndSUsHh5jcaLgFJ2QcYL4AiBC0Ra0+uk7RmRr75ym0y1SBWwxqRQCihRQ99Cl79jDTA=="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.43_1529235626011_0.8474532956584686"},"_hasShrinkwrap":false},"0.1.44":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.44","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"main":"lib/index.js","source":"src/index.ts","typings":"lib/index.d.ts","typescript":{"definition":"lib/index.d.ts"},"scripts":{"clean":"rm -rf ./lib","build":"rm -rf ./lib ; npx tsc -p .","watch":"rm -rf ./lib ; npx tsc -p . --watch","lint":"npx tslint -p .","link":"npm link","global":"npm install -g ts-node typeorm typescript gulp serverless tslint"},"dependencies":{"apollo-server-core":"^1.3.6","apollo-server-module-graphiql":"^1.3.4","aws-serverless-express":"^3.2.0","body-parser":"^1.18.3","express":"^4.16.3","futil-js":"^1.48.0","graphql":"^0.13.2","graphql-iso-date":"^3.5.0","graphql-playground-html":"^1.6.0","graphql-tag":"^2.9.2","graphql-tools":"^3.0.2","graphql-type-json":"^0.2.1","graphql-voyager":"1.0.0-rc.15","jsonwebtoken":"^8.3.0","lodash":"^4.17.10","ms":"^2.1.1","reflect-metadata":"^0.1.12","super-graphiql-express":"0.0.2","typedi":"^0.7.3","typeorm":"^0.2.7","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.0","@types/graphql":"^0.13.1","@types/graphql-iso-date":"^3.3.0","@types/graphql-type-json":"^0.1.2","@types/jsonwebtoken":"^7.2.7","@types/lodash":"^4.14.109","@types/ms":"^0.7.30","@types/node":"^9.6.22","@types/uuid":"^3.4.3","aws-sdk":"^2.259.1","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","shortid":"^2.2.8","ts-node":"^3.3.0","tslint":"^5.10.0","tslint-config-airbnb":"^5.9.2","typescript":"^2.9.2"},"globalDependencies":{"@types/del":"^3.0.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/merge-stream":"^1.1.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2"},"gitHead":"ffa70f445d3e666a15287da69547ac8147951986","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.44","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"dist":{"integrity":"sha512-7hSV7DH0P6tmpNi36AMt3TkTPoXMIY80DTHA+eLC8R7x+1/kJEE8Za1EONnQg9nkxjwX2Sg7bp92+7ZZOWuyNw==","shasum":"eda315906e8eee6cce0c8d37089d629c061749cb","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.44.tgz","fileCount":346,"unpackedSize":1014632,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbJwLqCRA9TVsSAnZWagAAqA4P/RkB5+Aib/1JjvZny2KC\nSW4INF74lyMT7G9KyFrTiJHIHMtv+mw1uch/BpYIFn30z/enitOlFpt8u81Q\nrnr2CEH0b+EvAkbL4XX9poxdE4ImqY40htsNJ9PfNExAlH8ihQDBxmY3ZtT/\neCcZneZlRw1ZKE+qzGrjTirhLu1Dj1k8vS9HgZYA5ZXS8MQOvEcMrqMxqZHF\nVqeGQExP6tzD2sdh4Iq2ObtOH/Dav2mUKp4gmbZnqYz7lYCJh3HpMUFX8og2\nbJB0VYMTMkLZ2mKzWleMzcALCTGkQafSAFEXqeZpDFgyJMry0kQh1sBcsaRO\nv6JRfFEQOKvaWgPU/OyVQO1IVzWTpTxJtfMB7Km0pYzGbT+aOUfSsBNsnxjG\n4QrN/cIAav3YmwhqW0ZUJW1tpEI4ggNNfWthb4g5FcP0DNaWz8YmLgbqjYK1\n8mjwZ13uaw2wT4GjajQLSQ7xltQdO28cNpGL1cZlKCo4DouG10CaVaUW3MHC\nqBqbHTOKAs+sZyh49UWXdJoSRUsoifV4FX8W2WsUlU6CExsnEubPtSWuYAme\nupi+VE5tBefCGv9txy6CbEb8m3RSR9OX74tOriCYoqqEWYMc6QaG8xcl+VfL\nyIJ3leIri5ctactqHuQv08fiHTFDqYvoBXxz9xVKsn7rQCLbUdTr0UH5M1tE\nNNg7\r\n=qh4T\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDTHR8bSKA5QKpn+5FhlnRCo+jFT5vxmRuqgyqwnqRZ5AiBML21yy7Q9n7CN2RE53oNuESTWE7b/O/gxNmF4dqc8nQ=="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.44_1529283306218_0.4649592041735102"},"_hasShrinkwrap":false},"0.1.45":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.45","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"main":"lib/index.js","source":"src/index.ts","typings":"lib/index.d.ts","typescript":{"definition":"lib/index.d.ts"},"scripts":{"clean":"rm -rf ./lib","build":"rm -rf ./lib ; npx tsc -p .","watch":"rm -rf ./lib ; npx tsc -p . --watch","lint":"npx tslint -p .","link":"npm link","global":"npm install -g ts-node typeorm typescript gulp serverless tslint"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"apollo-server-core":"^1.3.6","apollo-server-module-graphiql":"^1.3.4","aws-serverless-express":"^3.2.0","body-parser":"^1.18.3","express":"^4.16.3","futil-js":"^1.48.0","graphql":"^0.13.2","graphql-iso-date":"^3.5.0","graphql-playground-html":"^1.6.0","graphql-tag":"^2.9.2","graphql-tools":"^3.0.2","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.3.0","lodash":"^4.17.10","ms":"^2.1.1","reflect-metadata":"^0.1.12","super-graphiql-express":"0.0.2","typedi":"^0.7.3","typeorm":"^0.2.7","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.0","@types/graphql":"^0.13.1","@types/graphql-iso-date":"^3.3.0","@types/graphql-type-json":"^0.1.2","@types/jsonwebtoken":"^7.2.7","@types/lodash":"^4.14.109","@types/ms":"^0.7.30","@types/node":"^9.6.22","@types/uuid":"^3.4.3","aws-sdk":"^2.259.1","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","shortid":"^2.2.8","ts-node":"^3.3.0","tslint":"^5.10.0","tslint-config-airbnb":"^5.9.2","typescript":"^2.9.2"},"globalDependencies":{"@types/del":"^3.0.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/merge-stream":"^1.1.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2"},"gitHead":"22573f467af81b3dd55f2b83d4aedeed92461836","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.45","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"dist":{"integrity":"sha512-3wkhAJb+QDuMfnBUgfGNEEN7sXdBjsZ+whPS3I9kRVa1vp7D0BFZfB3j71kHDL8m0NMe/rt/1ggpInFb6ciCrQ==","shasum":"9ea9d972042fc6094ad7e01e744fbcf440d85c15","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.45.tgz","fileCount":355,"unpackedSize":1041364,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbKF2ICRA9TVsSAnZWagAA5PYP/2CETNyDiGxE0Zrx8e8/\nMmyBRV6ZsRgjCU/G6rVUkI0IGkAGgGwCiATPXC8ed7sQHWop0IJoSZFYmjjQ\nAgx+SAUSr/+hb7oP4Jk7EWfIeorHQ5/LAVuF6CpRF2BkGQnQjmKhjbpngQWv\n9xZqSIm210ksakwwGP7liwVDFeqQoZ7w3AHtJB/iWUspyrgmmrD7w2movtfA\nvoI1fiDJ/ZOcu0m6K1P3CIPKLL9o69tNbHOqcaM5xgVPNAFAf3WBHud5s+ix\nnNe54eQFkHoTLdBkkbhgnn2dDJcV7tLtHnS3vnPZSLLr7WKdYjaqbV9TCWSp\n5T/+xR/CrPmi0no/rJTwQDClaImsY/4JFMRjzYhXuSs0ordTq7ixnpIy/J3G\nFtUX+D18ujCix2Nnqtik6rqfPSu7j/5xzh1GgDspPN+/CHhMqncmFiUpOaem\noEtSwMSFOHQZcNi5AIolyRg8juOmhMoslVlxheFb1U4hLXULVIk7rm4lHVgo\n2M0NbDlW37tGB615l38aLJ/dWB1x4soA6Fj09hz7+PHxn2pAKtkpeuwPUGm7\nTig/VxGL6L9BnTZDEUwwogKBt43+ygHlT/c9z59nS5WuZCy1SVaj60F6A7el\nlyxguB5yeQ4WxwnVxmf6hk2EDkMUSrJlAH50OYBJNAdsBdaOtE7/hlnelKDz\ndfek\r\n=vj2d\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHTwBrF5iz4Iib79NBbqgOiIgswQqCw7frqpFSV0SeX5AiEA6lL0aU0sY0a8PdqAaUcae/G2WrCjniOfIDCi0XXq8uY="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.45_1529372040055_0.7664543543880253"},"_hasShrinkwrap":false},"0.1.46":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.46","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless"],"main":"lib/index.js","source":"src/index.ts","typings":"lib/index.d.ts","typescript":{"definition":"lib/index.d.ts"},"scripts":{"clean":"rm -rf ./lib","build":"rm -rf ./lib ; npx tsc -p .","watch":"rm -rf ./lib ; npx tsc -p . --watch","lint":"npx tslint -p .","link":"npm link","global":"npm install -g ts-node typeorm typescript gulp serverless tslint"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"apollo-server-core":"^1.3.6","apollo-server-module-graphiql":"^1.3.4","aws-serverless-express":"^3.2.0","body-parser":"^1.18.3","express":"^4.16.3","futil-js":"^1.48.0","graphql":"^0.13.2","graphql-iso-date":"^3.5.0","graphql-playground-html":"^1.6.0","graphql-tag":"^2.9.2","graphql-tools":"^3.0.2","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.3.0","lodash":"^4.17.10","ms":"^2.1.1","reflect-metadata":"^0.1.12","super-graphiql-express":"0.0.2","typedi":"^0.7.3","typeorm":"^0.2.7","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.0","@types/graphql":"^0.13.1","@types/graphql-iso-date":"^3.3.0","@types/graphql-type-json":"^0.1.2","@types/jsonwebtoken":"^7.2.7","@types/lodash":"^4.14.110","@types/ms":"^0.7.30","@types/node":"^9.6.22","@types/uuid":"^3.4.3","aws-sdk":"^2.259.1","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","shortid":"^2.2.8","ts-node":"^3.3.0","tslint":"^5.10.0","tslint-config-airbnb":"^5.9.2","typescript":"^2.9.2"},"globalDependencies":{"@types/del":"^3.0.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/merge-stream":"^1.1.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2"},"gitHead":"484db512868d33c4f053c4ad6eec40b0cd7db9ad","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.46","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"dist":{"integrity":"sha512-GUvEjV0XUJjLzsZHy+bHw8j1Afxqxb6hFKR1UuiqycYII+kpBrxR8woxUsSzAjPecblGFuse+J5dJbzX9VE0hQ==","shasum":"291ff177764f062518ef9e7fa65efa1e82cc0ed2","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.46.tgz","fileCount":359,"unpackedSize":1050086,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbKbSuCRA9TVsSAnZWagAAWn4P/ibcQkrYqNSXNfQ9sESx\nibx+K1rv50INxayUL5Bch0q/xuS9SYJPaaHSzf8npxzSchKjczvhMtSxeSz0\nRS4JlCf5D1Ca1Yw8tC6MPSsB5/KnotxH/HPH3UTaCEeNXO1oOCMwS1Z6E6eI\nKyoY3SgOV33RadKxI5vmbgRu+mep3W4qGibsMGEPumg5c8ZTlqQ0MxlbXm3B\ncKZM/6W4CuOxSX2/nTflK61YqH9z2bMd3TCdB0BQbNIdVu+wKzUBOVhQKP87\n/IB2qSttu/D4/OH1ymzYf6NMSFO+nDVyi9sVY2nEHNIHa8/PdWFbaEveoWA9\nCIb2IcKahf1mz4ZPkHD6gj6ok7TDFlG9JVhVGNoau4Y0vRtNLzFkaNjzv4vd\nVwLTJttd3R90qtZsriR2TwhbcOZUM5oQAIqY/rCeuoUyBzAIp+WFOTjiP/yE\nk8UiAQ6X74g70Z22de8psz0eQVwi9Eq75eCiIbUNbGOakDwXNekxhQrM7bAx\nHsLPRtk7ckM1e/ddfWrr7JFFq1xh9SvuS/u6/gJWiMX845c7LJynzik1fZBA\n6T02X7RhwF1bqMIDL4aGp7HRclPxFSBorzBkJFvOvd4XPAKTLJBMvx37cWzl\ngg9ZJTuRq+tX+JHeA1ujn+OEZOFvAb1umFj8NCsXkv2lW8iFLnpOHwx0NZ1U\n4aiO\r\n=3LWl\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCTNEJRy3sed8Pf+iqTOUTkv2UpI4Ll1pxJY5ODoErdCQIhAKN2rlWf8XXLt8jRbtiNbTPsNVddlkRHjrYoUCfRawGN"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.46_1529459886411_0.27011571172944726"},"_hasShrinkwrap":false},"0.1.49":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.49","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p .","watch":"rm -rf ./lib ; tsc -p . --watch","lint":"tslint -p .","link":"npm link","global":"npm install -g ts-node typeorm typescript gulp serverless tslint"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"apollo-server-core":"^1.3.6","apollo-server-module-graphiql":"^1.3.4","aws-serverless-express":"^3.2.0","body-parser":"^1.18.3","express":"^4.16.3","futil-js":"^1.48.0","graphql":"^0.13.2","graphql-iso-date":"^3.5.0","graphql-playground-html":"^1.6.0","graphql-tag":"^2.9.2","graphql-tools":"^3.0.2","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.3.0","lodash":"^4.17.10","ms":"^2.1.1","reflect-metadata":"^0.1.12","super-graphiql-express":"0.0.2","typedi":"^0.7.3","typeorm":"^0.2.7","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.0","@types/graphql":"^0.13.1","@types/graphql-iso-date":"^3.3.0","@types/graphql-type-json":"^0.1.2","@types/jsonwebtoken":"^7.2.7","@types/lodash":"^4.14.110","@types/ms":"^0.7.30","@types/node":"^9.6.22","@types/uuid":"^3.4.3","aws-sdk":"^2.259.1","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","shortid":"^2.2.8","ts-node":"^3.3.0","tslint":"^5.10.0","tslint-config-airbnb":"^5.9.2","typescript":"^2.9.2"},"globalDependencies":{"@types/del":"^3.0.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/merge-stream":"^1.1.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2"},"gitHead":"dfcf1175ebadcf1b206c51cf994d4000f3ec041b","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.49","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"dist":{"integrity":"sha512-8YhmUE0k+gV7Od1xe/+TGCxgRUtw/l1P+MEppdzrhc4kCyMcTb1cHdg1j6qlJ4kN/w59BW8Nh/j2LFkDZkxxlg==","shasum":"2bf0cff6c32b8eeb8dd25c8714ecdf690f1a8e65","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.49.tgz","fileCount":359,"unpackedSize":1039828,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbPK31CRA9TVsSAnZWagAAuhQQAIZtM8zWeavxva/HWoGf\n09g/vRbBcWtFdUe6aa7xkgbVlhTKQwkkzwwnKGCZjZn3YksF5ZUFV6q5gbNJ\nR2Aep/XMxPDPPlIYkdkLlBY4KpkEPtr9tLRD+Nmw8xHfkjxrNaYFHjwqhZt6\n2ord0EegMY93km5Y1VAFefYzJQopxbl3/MkYBcf1Wfdu+y/ev02LX/MVTNOT\nbUlkFt6pHlEWWld0pVTmXMiiXQ0YDvVmfFoeJazCCeXX7dJxB0Un+gBlPCG/\nVPM+CR8zVOKHXcdpdyYGhen87Q/aEsBM8SOoMuOasq/kKJwVVABf7D9xURvp\n+V2+yDzxlvrXw/hWwV34VDJ4z7027dpAghU+cLm6HvNWHxxBvTpVAQ3WuG8M\nlfOtYsVPtXdK3HbJmW8ZdlGRwBl8ZFMWbSJci9Bp+zG+8LGtaBSDdO+Xyipb\nEaCXgGJlmzU4hv1ZSZSpNN+eymAbc/0A2n/LdMWY3Q51yoCooQPGCiWeOiod\nDx7WyfAGMW6JYHFwuupI/fJRt8C2qm1wLf9WhSxcm+osI0Ds+YmKyEX4vVzp\nm39bPQFTmJTGBl0t+0p59slsIdt0ZdB08CbH1Ti4SrPIncaGNbSC6F6NSBKi\nhppYql2VXZg/6nmQwu5hAsIp/6alUnPYyhz+FL0sfjZbTMNB3suEbUl4UFrS\nkSlp\r\n=ag6U\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDQLhrNla+QucmxXG2BjaUkwOC6aHSf8L2y2Fhg9RLieAiAV+oT53DGlEm/1x7rkvEm1f8Y6X9bWFpS6UiEwqKaTdg=="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.49_1530703349565_0.9860144932765145"},"_hasShrinkwrap":false},"0.1.50":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.50","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p .","watch":"rm -rf ./lib ; tsc -p . --watch","lint":"tslint -p .","link":"npm link","global":"npm install -g ts-node typeorm typescript gulp serverless tslint"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"apollo-server-core":"^1.3.6","apollo-server-module-graphiql":"^1.3.4","aws-serverless-express":"^3.2.0","body-parser":"^1.18.3","express":"^4.16.3","futil-js":"^1.48.0","graphql":"^0.13.2","graphql-iso-date":"^3.5.0","graphql-playground-html":"^1.6.0","graphql-tag":"^2.9.2","graphql-tools":"^3.0.2","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.3.0","lodash":"^4.17.10","ms":"^2.1.1","reflect-metadata":"^0.1.12","super-graphiql-express":"0.0.2","typedi":"^0.7.3","typeorm":"^0.2.7","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.0","@types/graphql":"^0.13.1","@types/graphql-iso-date":"^3.3.0","@types/graphql-type-json":"^0.1.2","@types/jsonwebtoken":"^7.2.7","@types/lodash":"^4.14.110","@types/ms":"^0.7.30","@types/node":"^9.6.22","@types/uuid":"^3.4.3","aws-sdk":"^2.259.1","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","shortid":"^2.2.8","ts-node":"^3.3.0","tslint":"^5.10.0","tslint-config-airbnb":"^5.9.2","typescript":"^2.9.2"},"globalDependencies":{"@types/del":"^3.0.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/merge-stream":"^1.1.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2"},"gitHead":"6d6ce0b7ffaa8f514a21dd0539c2f22430c8471e","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.50","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"dist":{"integrity":"sha512-QdCoY+dYYuXrTnu6Tay2+FzQmshRZnljthgM2V3nxRZCykoYMNGkvQXO/DiHgfbjny9Qhpo8qeVserl91PXmSA==","shasum":"31f0ccfa4bd3743e43cc9858772736c56493b3f1","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.50.tgz","fileCount":359,"unpackedSize":1041353,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbPMDbCRA9TVsSAnZWagAA5OoP/jOf/c/4i2es2gQUXPY7\nSfv9NOpnyehQqFZVuX2AQqHvIdtMROZKpHIMsLXek9OkhnvF8vN/wp9yiiJF\nz58Uou1iBjUFh7UXoOeIEwk+AiXyRJrtj6hnszcmaWMs4IzYzH3FL/sWJ+8k\nCSFbBz9XZ89d6E/II/4PJPIZmMttyfLzLtsrC+b38hWd4b8JM9mLiRw1L/Xl\nJNgDx6on6C0M0iF/tgeI/Yt9GRnwSTXjjsxkOKQf+6wqRXC6cf1ejgoQteOG\nIDyojDewuUhwoe+Wai6HvYqtNSwNzPXwa+52iq9Au7hwPsdnXB/UL2gWV0sF\nKdeJ502it0PxhGTnEcyOefEaiPeAVu1A37l57/d+2GXYoNT3SfkFSrXCqu+o\nv7teltKLHdQPZ0Ww6X74jZdMaTwK7od/5zmZ0xwMWF4/j3aOyKktxDeRaTA2\nBlfXuMFb1ScnVyB9ZtQL6oZ2cidpbKQgZDhNK9w8EzCIUDN164XNRhMX8zSJ\nvwFroAvCs8M1AsfKApUatnrW0722kn1EWhYJgNbSkqmz48NiDiYBLFQtxjZU\nx2l3DG9NFNPbtaXnMkI5uobhrNrD+JfRZDPOq+LxgmS6d6WBbDk2E17SRHVL\ngueBTTur2MsLUxErOUL8O5OmmMZh/fV7vvPxuyFckE65B8wdO+hdsSYBUz9c\nbkd3\r\n=Ckcg\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDkGZvmrRDZypxQehk+zoBkTxKNbl9uhiOmSmxNYRlrEQIhAOUsZuAfotQunjelJavNKwGX5eIaiUtDIicxKWTrSB0F"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.50_1530708187126_0.9550209018490479"},"_hasShrinkwrap":false},"0.1.51":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.51","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p .","watch":"rm -rf ./lib ; tsc -p . --watch","lint":"tslint -p .","link":"npm link","global":"npm install -g ts-node typeorm typescript gulp serverless tslint"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"apollo-server-core":"^1.3.6","apollo-server-module-graphiql":"^1.3.4","aws-serverless-express":"^3.2.0","body-parser":"^1.18.3","express":"^4.16.3","futil-js":"^1.48.0","graphql":"^0.13.2","graphql-iso-date":"^3.5.0","graphql-playground-html":"^1.6.0","graphql-tag":"^2.9.2","graphql-tools":"^3.0.2","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.3.0","lodash":"^4.17.10","ms":"^2.1.1","reflect-metadata":"^0.1.12","super-graphiql-express":"0.0.2","typedi":"^0.7.3","typeorm":"^0.2.7","uuid":"^3.2.1"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.0","@types/graphql":"^0.13.1","@types/graphql-iso-date":"^3.3.0","@types/graphql-type-json":"^0.1.2","@types/jsonwebtoken":"^7.2.7","@types/lodash":"^4.14.110","@types/ms":"^0.7.30","@types/node":"^9.6.22","@types/uuid":"^3.4.3","aws-sdk":"^2.259.1","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","shortid":"^2.2.8","ts-node":"^3.3.0","tslint":"^5.10.0","tslint-config-airbnb":"^5.9.2","typescript":"^2.9.2"},"globalDependencies":{"@types/del":"^3.0.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/merge-stream":"^1.1.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2"},"gitHead":"cac3715af183de3e0f622f82c0bc7c4266370a9b","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.51","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"dist":{"integrity":"sha512-sLTLTF+/QoqcY4K0t/6o4K/x+OtrpVAS3Sx6WjWLo7JjMPVhbCwiyS+2QEbGhCqush8vqJPJWV9GeA7BjfDbMg==","shasum":"b8b6262520a5b47f4f45da9dd2640ed39c7901cd","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.51.tgz","fileCount":359,"unpackedSize":1041520,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbPM1nCRA9TVsSAnZWagAAkiwP/jUFgeD8vJouU5PShW8U\nZVYpBYlDdYnuPwAni1Ar329TheKERhW5OGAXe72yTt7q+EM//lWG82wxjyfZ\naz64S/1q4dYBK1vt+Fh91I8YvG4XSAQ+RsyojMmHuhPCtiLR3VFnz5iXSARa\nJYNwAvx4iHSKCxIyeoMkEcJnWEqrowHgI2UX8SZwlRRD2maMZHnaFdugpet9\nj414zaK85lqRMCXFIVDbSYhff7YZbdPdTRI/UOIwD9ITTU0QisVsaTOSUslt\nYN5hQyfJlyZhV44DRyQTmBlka1e+42sJTUk4A+WbzB8ochk7AwYw41gGZopw\n+s2vKLc2g3PtJRzKtpbiqlK1geeSAIFpOGFt+X63eaSEKEOakYKf3p8aQIX7\n1bP+s6srDfIRi5OLgL0VgDbycG5+vzVcKbuGSgvlkVW+ce8P3U8IPVcA8cwe\npjZp5GO5QDOLsfif5lAx/m3irB1Utk4Ly5wUH91YRh9l9A+LQIiiJdk38TLM\nRBHgY1bXhQWi9WxQyl14l4qFk81R5rnEu6vGcczBtKjnqZhvDZWfCogP3TyI\npwbbzGCErw3a7zgAMTuA2BJ8dvfuOnJPP6bXt+1ATRCAp5Eb7ybgeFr1FiUr\nwDkeNYthZV9LCANYXeJhVZem1hFhCPOQ8XMBNR36uMahWBRWb13vLtytDBrl\nEOsq\r\n=HDFu\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCBsahQ6ENVI0lz/QdBqSS8DTcSm+x4CBAzntTBYxUBKgIhAMht5HXTmmaHa9vgc1lnpUpqax16XOwCaByo48PIuoZY"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.51_1530711399579_0.2601048761562763"},"_hasShrinkwrap":false},"0.1.52":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.52","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p .","watch":"rm -rf ./lib ; tsc -p . --watch","lint":"tslint -p .","link":"npm link","global":"npm install -g ts-node typeorm typescript gulp serverless tslint"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"apollo-server-core":"^1.3.6","apollo-server-module-graphiql":"^1.3.4","aws-serverless-express":"^3.2.0","body-parser":"^1.18.3","express":"^4.16.3","futil-js":"^1.48.0","graphql":"^0.13.2","graphql-iso-date":"^3.5.0","graphql-playground-html":"^1.6.0","graphql-tag":"^2.9.2","graphql-tools":"^3.0.2","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.3.0","lodash":"^4.17.10","ms":"^2.1.1","reflect-metadata":"^0.1.12","super-graphiql-express":"0.0.2","typedi":"^0.7.3","typeorm":"^0.2.7","uuid":"^3.3.2"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.0","@types/graphql":"^0.13.3","@types/graphql-iso-date":"^3.3.0","@types/graphql-type-json":"^0.1.2","@types/jsonwebtoken":"^7.2.8","@types/lodash":"^4.14.110","@types/ms":"^0.7.30","@types/node":"^9.6.22","@types/uuid":"^3.4.3","aws-sdk":"^2.268.1","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","shortid":"^2.2.8","ts-node":"^3.3.0","tslint":"^5.10.0","tslint-config-airbnb":"^5.9.2","typescript":"^2.9.2"},"globalDependencies":{"@types/del":"^3.0.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/merge-stream":"^1.1.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2"},"gitHead":"eb5570c83b07e84e61d11e9b1b3fd8650e0c243a","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.52","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"dist":{"integrity":"sha512-88+c9l5LG3QnKp4VgksNqC8NAf1ZZ3V1SJR1xhtGWlqGpSx59CoUm2ihwAnwG1leBSHSCa3NVr3FZagArXbvnQ==","shasum":"26701eda80a658bbc56e8b38d606fdb0ed470681","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.52.tgz","fileCount":359,"unpackedSize":1041724,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbPNvICRA9TVsSAnZWagAArnUP/2RHFhQxGdrgomgEaQ0G\n2znn3cUGjxPtnDfr/MuLxfriEMNqmWjYnH9Qf2Uq48mTwKJhASRvAvMgtS9f\nu1jhin2oWJE8+Luiz+Hiq24vDox8jbCS8GCnuVVT73XK8Cugwo76tBbj13Jt\nIl5jlh/yPXaybrxwMBbXPI1mflx8gVssmlPGQA6h/oTHXqWMsXwX4tzjrUy2\nWyHVjy6Bv6Zqt+A0x4IiL4AkZ7paBjrR1CFJvmxv+wuWSBNC4jgz0HMGsXGb\nqbguXLhx9S0IVNs4xJVwrucMAj5inSFpv7G/T1xN6QiByut/uRQvX0WyTl/V\nXvNEH+k6wnBeVz0H2kCFWUIPG2Tjy2IJzzXpVKroWtlzQr/2CyurkOjpx83X\neQGwhiPo82k4o3IIeNxJw8W5VuOpWRVosfAB2KGccRnglu05VN8GOJurE55l\nm+zNsAT4DVEiXZgOjBNyRC3F3Np/c+6DkbkBD1DrDPmNgcov8c04j2+sAeuV\nDCsnOeFaqz4E7ab4XjutUVJvMVqF+L5KAaPJA7Q53S1XcemMYDMqCtqbmPCf\nZ/acnbJcqptmeHqrSZxu1PwvAKKvAWy//cXWY05dNEhGK9R2Z5GDyq/y6esX\nDRbcYsC8ZZpTbsh7OWixx6jzOKi08Bju3RTpbsdSW3ySo0YLT/5lK3znOcxm\nnFFn\r\n=AO4W\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHa6A5NonvWiFdK425Zu64lD80giouI8ZDyS3fccwV3+AiEA6YnSuPDzRl8LMKPH1qwrSOG8rWDEwVXCrWPvtRwNCRU="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.52_1530715080705_0.5892689158657769"},"_hasShrinkwrap":false},"0.1.53":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.53","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p .","watch":"rm -rf ./lib ; tsc -p . --watch","lint":"tslint -p .","link":"npm link","global":"npm install -g ts-node typeorm typescript gulp serverless tslint"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"apollo-server-core":"^2.0.0-rc.6","apollo-server-module-graphiql":"^1.3.4","aws-serverless-express":"^3.2.0","body-parser":"^1.18.3","express":"^4.16.3","futil-js":"^1.48.0","graphql":"^0.13.2","graphql-iso-date":"^3.5.0","graphql-playground-html":"^1.6.0","graphql-tag":"^2.9.2","graphql-tools":"^3.0.2","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.3.0","lodash":"^4.17.10","ms":"^2.1.1","reflect-metadata":"^0.1.12","super-graphiql-express":"0.0.2","typedi":"^0.7.3","typeorm":"^0.2.7","uuid":"^3.3.2"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.0","@types/graphql":"^0.13.3","@types/graphql-iso-date":"^3.3.0","@types/graphql-type-json":"^0.1.2","@types/jsonwebtoken":"^7.2.8","@types/lodash":"^4.14.110","@types/ms":"^0.7.30","@types/node":"^9.6.22","@types/uuid":"^3.4.3","apollo-server-lambda":"^2.0.0-rc.6","aws-sdk":"^2.268.1","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","shortid":"^2.2.8","ts-node":"^3.3.0","tslint":"^5.10.0","tslint-config-airbnb":"^5.9.2","typescript":"^2.9.2"},"globalDependencies":{"@types/del":"^3.0.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/merge-stream":"^1.1.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2"},"gitHead":"92ca27295eaca2d827c4f462a8633465a6d352d0","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.53","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"dist":{"integrity":"sha512-w45hpBj10IiKGhekhGJk8GzJeN4LqKuKDo5gA5mmxEeXcp85eJCu9IWDl4dbq+etzucMs08gQvZLRBaJgQ9P2A==","shasum":"30feaa19f0fac3fe1a9f88ac71bd6e0c8d81eb43","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.53.tgz","fileCount":359,"unpackedSize":1042367,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbPQonCRA9TVsSAnZWagAAUAIQAJBepvlo2QHOSkI/Rr/F\noV29dtEyNRlpaXfNPKkXbwOJvXn19S6F6+7+7pNSeMb5RUKL0ZzeL4W+oKHv\nd9VOgVcsrl27CRYePXRGBhbR/6cfjvmIkno7rzTVkOUPbDtqhBgG1JpRACCm\nUSxypAzv1OPeT897ZLhoSDj7PjU5uHAFG5K80wtnK040vS4+mUt4EYzszg4L\n9Y0r+Z2OQKxdXSIeMJ6tiWC94QTB3FMs3C9gaDkn/NWBYEx6SawYvs6xMrVc\nNwlIdbLWgLG1xKwkdEQ76iIygd0udRSWUOSuoZvBk9qtr6BGYly2VFvg8Iqn\naHoBLjns1t5WUEQ81+heUrsSPENLE+lgdwzHqoHF0dWdEuJ8zxPZJnqAEKOx\n/h0+Z2VFEoMyZgcDIl2kwEvTsqLpMArAugK63T9nnMhC8yCR1idwZs/0aTgS\niUvUtXo1XiPUJu7lhTee/mzLjgiE/MYqj22VLipo+fW8MllWYjy2hhhXA9Tt\nJOl07xDDt+6layDop2vGg3b3UwM2B2qwteWkVELy0uQ3KgkFtfYHS81uV+hQ\nf0mjlJpQRUyEUTAQnhT84WmRo7nA0rESkgxsl+a7sAl0QtB0SNkXtjKrXVTs\ny9GginYp9I7BRWcqHB29PhihMzBs8M8YeocXLreJbtluFSyJsanBkLFz0vj1\nR1It\r\n=HX77\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGDKsOaGks4n4ajAeFGxDj7ZG19XDwDDh3+uNc8WZB96AiA28uc8pojrnysS81yQHHJqxR+7F3rR2YN1fFG8khisJw=="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.53_1530726950968_0.12541107528577622"},"_hasShrinkwrap":false},"0.1.54":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.54","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p .","watch":"rm -rf ./lib ; tsc -p . --watch","lint":"tslint -p .","link":"npm link","global":"npm install -g ts-node typeorm typescript gulp serverless tslint"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"apollo-server-core":"^2.0.0-rc.6","apollo-server-module-graphiql":"^1.3.4","aws-serverless-express":"^3.2.0","body-parser":"^1.18.3","express":"^4.16.3","futil-js":"^1.48.0","graphql":"^0.13.2","graphql-iso-date":"^3.5.0","graphql-playground-html":"^1.6.0","graphql-tag":"^2.9.2","graphql-tools":"^3.0.2","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.3.0","lodash":"^4.17.10","ms":"^2.1.1","reflect-metadata":"^0.1.12","super-graphiql-express":"0.0.2","typedi":"^0.7.3","typeorm":"^0.2.7","uuid":"^3.3.2"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.0","@types/graphql":"^0.13.3","@types/graphql-iso-date":"^3.3.0","@types/graphql-type-json":"^0.1.2","@types/jsonwebtoken":"^7.2.8","@types/lodash":"^4.14.110","@types/ms":"^0.7.30","@types/node":"^9.6.22","@types/uuid":"^3.4.3","apollo-server-lambda":"^2.0.0-rc.6","aws-sdk":"^2.268.1","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","shortid":"^2.2.8","ts-node":"^7.0.0","tslint":"^5.10.0","tslint-config-airbnb":"^5.9.2","typescript":"^2.9.2"},"globalDependencies":{"@types/del":"^3.0.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/merge-stream":"^1.1.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2"},"gitHead":"f6939b1b27dcfa30fc6d924bfc07ced0b4d7acda","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.54","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"dist":{"integrity":"sha512-vuTyGrnGyEFA6ew+Z/7XttrsSniFD8xVAwaxe00cmntzBb22yGbBTky1+Cdkw8p9S89W4HkOMn+melFjfx0Mkw==","shasum":"a9d87d0f4d9bc334f04a60184a744980a28cd36d","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.54.tgz","fileCount":360,"unpackedSize":1002934,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbPWo/CRA9TVsSAnZWagAAZVEP/iPz6xN1Mwip7de0PxJh\n/Rj2ic31MotumROFqo2B4cboKWM5IRlRHcUXOrg0GTVAm0lMgks9rThZzRHP\nvbF+jxwKIsSWqAT7CFN9Tqyx0j1QaYMUZ/J/6bzRPoFWWhIItb+nrnaZOX0S\n+S8hd0dZvc2nUI5UaGuzIMTT+Y3UUfvmePN77T+F/Bw7wPGLQeQ9U04xoIom\nQ8KKO8A4fa3rGGR7OAcHF120p3Zn1ccH5WiVqBW0s+Ay6O+Q4emM7BYXliTl\nVwNOltF/AAslt8MWjpuKJbnh6c7olMWf7op69ALyaGDVnWTg+g7TNlrCIJAr\n0RVATdMEmTsGqTOPdM7ybQkvZnss9oB/rUUwiRutpvoch/H66jUT3v9VV9BI\nR6uQDtzhJdZRd19rEi3rQmNYZm+oDaAVxQzhZiJiyxFI9VwW4/P8UKCUe8gR\nDFDxMzqe+Jjm6RH5jjOPWpbALZZY5X/XrG3z9c6ustYVEmdSH7iuxnjB5pDg\nbJRDFJqMWxx1hqI9FJwAHR2q9zttkzNfeF71+E1iytiP+5q6e2TTVAVhLYO4\nURzTuIsOLfzu/9hV1nBGIc7MCuFwSIky+T6lOxS+Yu7FaDKkqV6GwXklcPvX\nHjUG+GMywK1fxQotKu8855E+BxkWbNKjOUDowlLJZkdTTcRlxWRS7Ft7yGsX\nH9pF\r\n=TsA1\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCxEKf/g1BKsBcX9q50nnU6xrM2jFuAdVGX5/IMjfEuMAIhAOvFAknFzqNzJ1YxpYveWh1w6MZ06uPh5buvVabhqVg2"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.54_1530751550907_0.8195555221684585"},"_hasShrinkwrap":false},"0.1.55":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.55","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p .","watch":"rm -rf ./lib ; tsc -p . --watch","lint":"tslint -p .","link":"npm link","global":"npm install -g ts-node typeorm typescript gulp serverless tslint"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"apollo-server-core":"^2.0.0-rc.6","apollo-server-module-graphiql":"^1.3.4","aws-serverless-express":"^3.2.0","body-parser":"^1.18.3","express":"^4.16.3","futil-js":"^1.48.0","graphql":"^0.13.2","graphql-iso-date":"^3.5.0","graphql-playground-html":"^1.6.0","graphql-tag":"^2.9.2","graphql-tools":"^3.0.2","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.3.0","lodash":"^4.17.10","ms":"^2.1.1","reflect-metadata":"^0.1.12","super-graphiql-express":"0.0.2","typedi":"^0.7.3","typeorm":"^0.2.7","uuid":"^3.3.2"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.0","@types/graphql":"^0.13.3","@types/graphql-iso-date":"^3.3.0","@types/graphql-type-json":"^0.1.2","@types/jsonwebtoken":"^7.2.8","@types/lodash":"^4.14.110","@types/ms":"^0.7.30","@types/node":"^9.6.22","@types/uuid":"^3.4.3","apollo-server-lambda":"^2.0.0-rc.6","aws-sdk":"^2.268.1","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","shortid":"^2.2.8","ts-node":"^7.0.0","tslint":"^5.10.0","tslint-config-airbnb":"^5.9.2","typescript":"^2.9.2"},"globalDependencies":{"@types/del":"^3.0.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/merge-stream":"^1.1.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2"},"gitHead":"ec653a6673ebb7db8c43ed2b35dff3e05f3f6074","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.55","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"dist":{"integrity":"sha512-Zml/Iz4JslURVNHgvje34Sbhcp4TXBrWtSM74XD/A+D+BdZVbp7Drz1AXZx+XCl9R6/KJYIcCOrZBB79Y2GHng==","shasum":"2b8389efb1d1c37b86dbbe8dcc1257cf99c7e5d7","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.55.tgz","fileCount":360,"unpackedSize":1011800,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbPZASCRA9TVsSAnZWagAABnMP/i1yYYTk0N43AhWmRzxm\n8hOKEIP/Sty6uQ2nVAm+HSJ3EnCAnsPtJBcefd+CHN7qSpaWSs+00LHfTeGz\nI1Vhr9mSrkYc/bTS+ICD0S6MRhPal7vfUAJ49v5hFjAQEc3HPyAPsLkphqB4\n0SZdUx4TywXJWL+FjcmU5EBV08WeFCgwfTb5LDghIK9hL5CIYL3XPU1GStJ3\npQn2pOWqv/DbeC9HMRZWbu7k3+MYiVUqsrxSf0/pxxqdg+IbtLor2/pZIrmy\nki2NFFs7akuYnHvOJqZL6IHuhz6e0c8aqSgoebyq+NTeKQTyGINMhnokfZKG\n5sMwc45FH41/M58i0unynC32K27+8hHLxyLuY9AtSd6GH+UKpzGZ2qOERy5J\nP8HBRI4tH9tHGQR70Fnzub35gKfwiPhH/1w9qzV4KtB49h7shKouuXbVhdSR\n9zY5GZDsz9Eg1oi/Zoa+Whb7wSvrHDy4KqFngTCEwQJJbR+9YKm/hnXBk6db\nQh2pXjPBfaZ+JKSUxvtt1cW0eLBwWem/6WLNhL46JDmFflguhiNhGzlLJ1ii\n3SsyGzF5tSRj/T7SCh36oAdTWtFunTTtNWLEEHdkYjaFqtM29yn+1xcmOUHF\nfZKQ0V1/jIBS8Y62RkIU9Ez/c08bL5ejkaq4J3IrKt4U/LimuDk+Q6EljR0r\nVZXk\r\n=PPWk\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHmH7S8A6EhgsgKGNgPP/RHJzqM71HRNQbnMVuYYpuk9AiEAgSO7Ykf0o5pkX+L5VIRKm4lOEix7V9mc6sA5lsN+YNg="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.55_1530761234032_0.9378351233644404"},"_hasShrinkwrap":false},"0.1.56":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.56","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p .","watch":"rm -rf ./lib ; tsc -p . --watch","lint":"tslint -p .","link":"npm link","global":"npm install -g ts-node typeorm typescript gulp serverless tslint"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"apollo-server-core":"^2.0.0-rc.6","apollo-server-module-graphiql":"^1.3.4","aws-serverless-express":"^3.2.0","body-parser":"^1.18.3","express":"^4.16.3","futil-js":"^1.48.0","graphql":"^0.13.2","graphql-iso-date":"^3.5.0","graphql-playground-html":"^1.6.0","graphql-tag":"^2.9.2","graphql-tools":"^3.0.2","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.3.0","lodash":"^4.17.10","ms":"^2.1.1","reflect-metadata":"^0.1.12","super-graphiql-express":"0.0.2","typedi":"^0.7.3","typeorm":"^0.2.7","uuid":"^3.3.2"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.0","@types/graphql":"^0.13.3","@types/graphql-iso-date":"^3.3.0","@types/graphql-type-json":"^0.1.2","@types/jsonwebtoken":"^7.2.8","@types/lodash":"^4.14.110","@types/ms":"^0.7.30","@types/node":"^9.6.22","@types/uuid":"^3.4.3","apollo-server-lambda":"^2.0.0-rc.6","aws-sdk":"^2.268.1","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","shortid":"^2.2.8","ts-node":"^7.0.0","tslint":"^5.10.0","tslint-config-airbnb":"^5.9.2","typescript":"^2.9.2"},"globalDependencies":{"@types/del":"^3.0.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/merge-stream":"^1.1.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2"},"gitHead":"255043825fc218cc9b79c2dc43fe2ecc96978fec","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.56","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"dist":{"integrity":"sha512-YUlMnXzI7yKxcDIaEcKuBO3rk9xmF/DzXJ5WjG7pdEgu5S9SCZG+yp+3PS4tuWgbauRY+7Mr9Durk8mZSkaigQ==","shasum":"394d348567173502c473ac6b419716736f282ae8","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.56.tgz","fileCount":360,"unpackedSize":1011802,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbPZhrCRA9TVsSAnZWagAAPEYQAKQF8JUtbUhz2EH7zXTA\nZ0PN69ju+yJ3dYt1z3qV28EcPhPqOF3L5VwE4ShDxi1O/SHbScT5LTyRWbq5\nGrnw7OBPQKEhe7pZ2oHyh0ZGD9loPbRlcSS/A4kBTOlGOIYWWjRw88mdav6D\nfXoAEH8nEZKXIKeHT41cR/ZD7jgpllXoTebtu1OnISdUB1zshi9JeVcbjWwf\ns6jCqLqJj4TYJ5swexMKTY61d4T2rIxom2VHqD/3G1D2w6L+fO2CvALc2RS2\nZ5XQIoeB2nTbbdwqttDMFhshAa2CUtF6XnfuqaL+Rl+kFQgrRwoD5CYh8tce\nzUO7rtD+bGmDJkI8cspzNPHlH6+9g6drb8X3OdI+DYWy+8JEOH4dAcUuY7oj\nMwOuVU5xBSlRolxCekmTxz+yWthZJAfVUyJgzRdvdlzw4lRZrKuifMZYW4J1\n2Y7qcs9J7Xjr9hmXFmhaVH9kJDYzThEJHEahcWPnqkvg2UGdIKm4qwZoLtTT\nmVJEWwQtQjRx3hDePjz7vkv/sjVy6NVzlD0Na6xJhtaxV9HYG8jY3bsWolyZ\nI3MRGC+fecNJiG2EsM+JEflZhSJgXW7lbpiEaE3cnj7q+LXBHQqZyPZHviCg\nAkaG4E3vhF0I3d2SUZbbPLQrwZhdhxuGK3CpLRjatw3x98wmJa/nX1F/54FS\nJfwS\r\n=QHLi\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHKvwPeIXlMKGoQFQFQjcaEnA3hXH9sBucLneZ64IRh/AiB5RLXrXyizwEFnCAcjYJfL0k8BfSsrX4aODHtHbC96eA=="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.56_1530763370855_0.8018701257648075"},"_hasShrinkwrap":false},"0.1.57":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.57","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p .","watch":"rm -rf ./lib ; tsc -p . --watch","lint":"tslint -p .","link":"npm link","global":"npm install -g ts-node typeorm typescript gulp serverless tslint"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"apollo-server-core":"^2.0.0-rc.6","apollo-server-module-graphiql":"^1.3.4","aws-serverless-express":"^3.2.0","body-parser":"^1.18.3","express":"^4.16.3","futil-js":"^1.48.0","graphql":"^0.13.2","graphql-iso-date":"^3.5.0","graphql-playground-html":"^1.6.0","graphql-tag":"^2.9.2","graphql-tools":"^3.0.2","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.3.0","lodash":"^4.17.10","ms":"^2.1.1","reflect-metadata":"^0.1.12","super-graphiql-express":"0.0.2","typedi":"^0.7.3","typeorm":"^0.2.7","uuid":"^3.3.2","wtfnode":"^0.7.0"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.0","@types/graphql":"^0.13.3","@types/graphql-iso-date":"^3.3.0","@types/graphql-type-json":"^0.1.2","@types/jsonwebtoken":"^7.2.8","@types/lodash":"^4.14.110","@types/ms":"^0.7.30","@types/node":"^9.6.22","@types/uuid":"^3.4.3","@types/wtfnode":"^0.5.0","apollo-server-lambda":"^2.0.0-rc.6","aws-sdk":"^2.268.1","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","shortid":"^2.2.8","ts-node":"^7.0.0","tslint":"^5.10.0","tslint-config-airbnb":"^5.9.2","typescript":"^2.9.2"},"globalDependencies":{"@types/del":"^3.0.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/merge-stream":"^1.1.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2"},"gitHead":"bd329d2c1cf06bf90114f43334975661bcca61c3","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.57","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"dist":{"integrity":"sha512-TKewKBE3VgK/xN0CWoxSumKqAWfK/Y4LMDzvUtfXfUByaogPAOk9icdUtRmh3rjRi4AWEPgxsdOYfRk/8EQu7g==","shasum":"b3ed24bca2dbd927231b983e7b112ba2895bd3bf","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.57.tgz","fileCount":356,"unpackedSize":1013706,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbPfe+CRA9TVsSAnZWagAAIZwQAI+bTtYyq4D6ofnejaIS\nmFOW7yyTyOuYpOVUEXEMhBW3CjvfFDXLTy719ABOSC+U1NjCJd/8qdh2CyFy\nEU1qeYGBPfsK/+geoX1/p647iNrseG5+KhadVH8O/jVMh2lVvmn9mwUzSRmb\ncdaCgRweVUze3cdvtnLnJiNq9uCdD2hj1/CFtr2AJOxcIgXHCnsFMUz0hsqr\nFMpqiC2GKDDCVvMkAMtGxpVGb+Vm3hNIorNKxVpjTtHUNQVtohxecpnuruzS\nFPdeVs9PVzxQs5BywHxMLm1bN2P6QFP9GOkKj3rp9Jo4aCTa1+EJVgl/ItXk\nCv9jslciGQjukH8NRKvNa8N4BUmeJ+rOv+IQ+WVnRII+XBCC0MQ1ssHNOvwh\ngNvfDS7tegUZBWq8XuIF0+F3zQYz4jUSZ+OlyjjoQmkKdRrOdpYawIaUYY4Y\nYINpsCezFsgQne07sfkC4bSOM2aBXTx7rfE6stKx3tI832CoK7+QbUwNrFSJ\nxaIrhUEFMN9xPnPEvnBDZBsPYYQiPVRyn7D9B//e5qIs14urLzgeViZSULVY\n5RHRvFn6WWmjtJAha+UYu7a1MzYLUd9udKuU7w+/MHGMaHeo0lUUtalePz8M\nKdCRjZrJVylH3EEBlBLyCIGpK8BDJ6nfmlWZTSGkX1y4HD5ISe8oMkwiVf04\nC/Hk\r\n=Z8K3\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIC5wKgGt36EosOzxKlcDTiJ4Q75r2qzu6sTH6gaOsqWnAiEAiwk80EAemiSgpEFET6gyqEfMbvsLmxmwbdoJo0fl10I="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.57_1530787774412_0.07676895028343833"},"_hasShrinkwrap":false},"0.1.59":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.59","license":"MIT","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","prepublish":"npm run build && npm version patch && git push --follow-tags"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"apollo-server-core":"^2.0.0-rc.7","apollo-server-module-graphiql":"^1.3.4","aws-serverless-express":"^3.2.0","body-parser":"^1.18.3","express":"^4.16.3","futil-js":"^1.48.0","graphql":"^0.13.2","graphql-iso-date":"^3.5.0","graphql-playground-html":"^1.6.0","graphql-tag":"^2.9.2","graphql-tools":"^3.0.5","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.3.0","lodash":"^4.17.10","ms":"^2.1.1","reflect-metadata":"^0.1.12","super-graphiql-express":"0.0.2","typedi":"^0.7.3","typeorm":"^0.2.7","uuid":"^3.3.2","wtfnode":"^0.7.0"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.0","@types/graphql":"^0.13.3","@types/graphql-iso-date":"^3.3.0","@types/graphql-type-json":"^0.1.2","@types/jsonwebtoken":"^7.2.8","@types/lodash":"^4.14.111","@types/ms":"^0.7.30","@types/node":"^9.6.23","@types/uuid":"^3.4.3","@types/wtfnode":"^0.5.0","apollo-server-lambda":"^2.0.0-rc.6","aws-sdk":"^2.271.1","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","shortid":"^2.2.11","ts-node":"^7.0.0","tslint":"^5.10.0","tslint-config-airbnb":"^5.9.2","typescript":"^2.9.2"},"globalDependencies":{"@types/del":"^3.0.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/merge-stream":"^1.1.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2"},"gitHead":"d6d291965c0132f4fe4a63d4a5a11b756ad21908","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.59","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"dist":{"integrity":"sha512-z02hiW22ybh08WUAj5QGxSgdfCG41eZcuVy15wWNcTF1jjXODA/RYO4aRL273lOPTIv3h5eclQqhmM/fW6gBKQ==","shasum":"09c59f6f4580ab459ca5914a5ee33274e3acd890","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.59.tgz","fileCount":356,"unpackedSize":1013960,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbRHeSCRA9TVsSAnZWagAANrwP/iAm122jHtFRZ1AeToJg\nBg/mYn4t/nK1028FF7sNGPNhQFozzp3EPibl4dpBJyPe7KzToWYHp279NK8b\ngJnrBGztX4njwm8NzL7DpNsIBE+g3krPGn2RgpVSJ6PtoXiG4DT8h8LoqLwF\nsRCG+YKmIONkCNrt2l9ZTGANuIvyV/8YX/pgcivDv4QTT1ruroVk3H/84RIQ\niY/JGrDelsugokwoQIJvXCsfLQytM0jC0n2k5P29cTLmUyt1LGoe3CajMGdA\nDZBZh59AhLvsO0i/qjvn6eNs0OtQA/ZHRxejCs7knu+k/Sh0lvnCrtzc4PgN\nkXFw0I1VFMi3pptip+M3/vOaT6BdYrQYNTeUFfmP/Kn3RbOACcE4DzBzSqYZ\nJVgsm9eJyOTJV+t+htN2A18wOF3UoMfXjKMDRJ0mClbYJuMxbb/uu0h4zEgL\nJYKKYzj5ytxu/g06ULF6RPiJNhxf7bGAX5hE4KyYGSflUT3hZz1fA56e2oWL\nzdofxDofe9qFbmO23C0kYTXjs6BSpHyTF3/I0J139Glc3+kgTsYEyojeuGYM\nt5yobz9U+HFsDoQYSRBNotNa6yaldpbn8zz2JyJOl9wnIZC1E9nd+/hGFY8G\nySMSw9u98YoQbS86dvOCVWfSUAskyn/hUDUfuhmmksighTH4+JGDAMRy+Vm/\ndkgb\r\n=1WA0\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFbpp4oI/CEUvhtMyBWiRVxItvfj7w0foYoqaX2bFe5aAiEAwLRgWBtYPZc8Vv/SHeXi9GdYOYhqNj3aHXHhg2sa1FI="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.59_1531213714136_0.28971735751247807"},"_hasShrinkwrap":false},"0.1.61":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.61","license":"MIT","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"apollo-server-core":"^2.0.0-rc.7","apollo-server-module-graphiql":"^1.3.4","aws-serverless-express":"^3.2.0","body-parser":"^1.18.3","express":"^4.16.3","futil-js":"^1.48.0","graphql":"^0.13.2","graphql-iso-date":"^3.5.0","graphql-playground-html":"^1.6.0","graphql-tag":"^2.9.2","graphql-tools":"^3.0.5","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.3.0","lodash":"^4.17.10","ms":"^2.1.1","reflect-metadata":"^0.1.12","super-graphiql-express":"0.0.2","typedi":"^0.7.3","typeorm":"^0.2.7","uuid":"^3.3.2","wtfnode":"^0.7.0"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.0","@types/graphql":"^0.13.3","@types/graphql-iso-date":"^3.3.0","@types/graphql-type-json":"^0.1.2","@types/jsonwebtoken":"^7.2.8","@types/lodash":"^4.14.111","@types/ms":"^0.7.30","@types/node":"^9.6.23","@types/uuid":"^3.4.3","@types/wtfnode":"^0.5.0","apollo-server-lambda":"^2.0.0-rc.6","aws-sdk":"^2.271.1","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","shortid":"^2.2.11","ts-node":"^7.0.0","tslint":"^5.10.0","tslint-config-airbnb":"^5.9.2","typescript":"^2.9.2"},"globalDependencies":{"@types/del":"^3.0.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/merge-stream":"^1.1.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2"},"gitHead":"f7db88fc0ea97a12759a5c41f7aaf24584a6006d","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.61","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"dist":{"integrity":"sha512-YdKpSya3nN8PaDoj/s8qyt/WtxtBFYqk32+3FaYXvL+hvp0p4nR+/vLCkQzOovujGFhDcQLuKgeOiDmoCU8Jgw==","shasum":"a608b76dff4a41af99a87edf881f49bd98026c58","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.61.tgz","fileCount":356,"unpackedSize":1013972,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbRHi7CRA9TVsSAnZWagAA9GAP+wRACitszUilE58Dmj42\n8W7D4v773yEgMjqP5eRnaYOWtfN75RJr9/CaYYs/ctGUeW8JM88NdUWTSnL6\nCCdewBDlyTDf6y47/0P6buSJA7go3FQIn9t6KzI7I5EkpV4EYVS5V907UrMx\nMQd/aU5QpklmHbPUoeQHZYxeDMsP+31RK8lAQhmKlJxqC5Id3AeXs6MBJQ+l\nFoJ3FENffcNBSmh/BcOkbaebLxvpRS1dlQHwiZFsacEaCg6qRhccljq4AyYc\nuL0i+kcJm8NFdbFsac1Hd8cSGv3R8tmLWEy2g0OSsk+sMa/uMIlb2KUc6iHS\n5tXI4CIKyCLLVoO6d8CE1Fx+B3Kyx6enXL2npi3cjc8LFxV2zJntTczYvTu9\nXOWIv9qp9O+E2+hr3LdT3uit2atS1Fn4G5TLxznncK3y0M1QwJeJavWb1Hsu\nxDW5jVk8VgoFzvi4ybJMnmaZqNJ97KIfFr9sr4p6NaVOzQ1QkdqV+pdFEwtw\nBUQRiCtpbOjk58oyNCaZKZ5wvkqOmPb3bJreUn5F6agcJNo5Ky0wRaqEWBGW\n4/BZ7wZSZ/YCxtTGbRQthiNof19cqGyqP7nWMpohd8bnhtm64DfA8GaKzJT+\nMFVE9l6hFXkEFKfuyQ7V7g6QOPNHpJf4t721FwqZ8SUuk7T0ABeSPXN1JHQ7\nWvp0\r\n=6Aj1\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD0VxGX5sNTqB7CZFc8uSIlXQNg3Y+c4i/vRNh9YhETDgIgU4q4rAonoFzBUfDqFKzxgUn9tOd1StAgspFeE25SXtI="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.61_1531214011019_0.9074599388101585"},"_hasShrinkwrap":false},"0.1.62":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.62","license":"MIT","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"apollo-server-core":"^2.0.0-rc.7","apollo-server-module-graphiql":"^1.3.4","aws-serverless-express":"^3.2.0","body-parser":"^1.18.3","express":"^4.16.3","futil-js":"^1.48.0","graphql":"^0.13.2","graphql-iso-date":"^3.5.0","graphql-playground-html":"^1.6.0","graphql-tag":"^2.9.2","graphql-tools":"^3.0.5","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.3.0","lodash":"^4.17.10","ms":"^2.1.1","reflect-metadata":"^0.1.12","super-graphiql-express":"0.0.2","typedi":"^0.7.3","typeorm":"^0.2.7","uuid":"^3.3.2","wtfnode":"^0.7.0"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.0","@types/graphql":"^0.13.3","@types/graphql-iso-date":"^3.3.0","@types/graphql-type-json":"^0.1.2","@types/jsonwebtoken":"^7.2.8","@types/lodash":"^4.14.111","@types/ms":"^0.7.30","@types/node":"^9.6.23","@types/uuid":"^3.4.3","@types/wtfnode":"^0.5.0","apollo-server-lambda":"^2.0.0-rc.6","aws-sdk":"^2.273.1","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","shortid":"^2.2.11","ts-node":"^7.0.0","tslint":"^5.10.0","tslint-config-airbnb":"^5.9.2","typescript":"^2.9.2"},"globalDependencies":{"@types/del":"^3.0.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/merge-stream":"^1.1.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2"},"gitHead":"3cc677f3b657715cffe6472b96f7018ca0cff857","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.62","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"dist":{"integrity":"sha512-uCappAVnP3h+H5uk/MbXYhzH2Y5Oj/9QnljhGOLQuTPAeMoaanFcVTY9thsnehRgksK3Cdyp4RVulxvrMF/mCw==","shasum":"f78cd8c6de2c43a2dba5ef5c82722d26bacbd067","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.62.tgz","fileCount":356,"unpackedSize":1017506,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbR0SzCRA9TVsSAnZWagAA/MYP/RBI+lkZfPHRqLAb2+IN\nytFxbuI+SXNZMJS+KhWOSjGrdihJeQahu0CFEiE3RL8O2jMXXwA/XazYIRq1\nTyALuUWYB3T7YSileizWoVJNMtZhzHx6AWekywCG1gbnEz1TcHG3l67Ist+8\noqnw4VfsrLKUrcwY4qtak4jQc/LPmWewTnfAM6Ky2yH+4KXRQ/U4DAmuvDzF\nBeRvOHJA0h8Zi+izN20LonHMCuLoniCE/zw0yOmqUqna80bGfkG4ZpKxRRfO\nhWNLvbg9CsVL4ULew76RvPIL5MzXHpXe627F5SJ7hUmDcYdcOVHendLJTYNY\ngpyz+ub4lTWN8ScdikUZj2XtcEBDhATUF5VMG6bfpzosxtUYSXX2NguxAKWz\n61o+rNk58gNDC30x+rkfufyyu2ZTl+M9SF6GXCeTOM1WqCnvbSLecoQgvhxo\ne4kS86/lJTJfgs+lUZitN5o7Sljc+yGbKOAIgQ4XuR8XPqshhxfxyNO1imqL\nLLv6+emdVjT1VK7iWnjAki9cbb1arphz1q9wkpzlhhlXZfHDzrfskfnAb4xS\nEqFZH568vISklGW1MaFLzeujedmBQDC/uN5eiYjlq1zGUEa56tYSqkkRVxNl\n2GMDsMLMy4/wtmOMXrxLw06nyGONsdCawqfi6uKrW9aa2yj5LXLytE42LZkd\ngdf4\r\n=gbhL\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAoyfO2RSn9dn4DqBPEhYE1jGPoczuoyvKsdRMU35JNXAiADoBs5JfsHmBpzK9nCAuRRKdwdB0gwUAB4WambI2SA5A=="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.62_1531397299432_0.024482276947797033"},"_hasShrinkwrap":false},"0.1.64":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.64","license":"MIT","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"apollo-server-core":"^2.1.0","apollo-server-module-graphiql":"^1.4.0","aws-serverless-express":"^3.3.5","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.0","graphql":"^0.13.2","graphql-iso-date":"^3.6.1","graphql-playground-html":"^1.6.4","graphql-tag":"^2.10.0","graphql-tools":"^3.1.1","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.3.0","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.12","super-graphiql-express":"0.0.2","typedi":"^0.8.0","typeorm":"^0.2.8","uuid":"^3.3.2","wtfnode":"^0.7.3"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.0","@types/graphql":"^0.13.4","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^7.2.8","@types/lodash":"^4.14.117","@types/ms":"^0.7.30","@types/node":"^9.6.35","@types/uuid":"^3.4.4","@types/wtfnode":"^0.5.0","apollo-server-lambda":"^2.1.0","aws-sdk":"^2.339.0","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","shortid":"^2.2.13","ts-node":"^7.0.1","tslint":"^5.11.0","tslint-config-airbnb":"^5.11.0","typescript":"^2.9.2"},"globalDependencies":{"@types/del":"^3.0.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/merge-stream":"^1.1.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2"},"gitHead":"92b0cb39414891e5086e5e5419264e4f7e196034","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.64","_npmVersion":"6.4.1","_nodeVersion":"10.12.0","_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"dist":{"integrity":"sha512-Iam+MyhjRcEc3bP35UDW3xbHmZOptnRDiYzZGWdlUaE/J5QJukgiVPYEY7ebpv80JWYyHr5aFPGz0SBay3KiRQ==","shasum":"9e1495a8c55cedf8ac1ceea061cb93a1cb99e411","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.64.tgz","fileCount":356,"unpackedSize":1017512,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbzN+xCRA9TVsSAnZWagAAKjIQAKNPMWztYbbTNJYeHnBd\njR9KBz1/91/Vn2VHtUk/+/KGcuoI8PpQjsG0E/w0hAG27ZalGbz+H/0bhTJe\nFmtUH1EbGQQrS//4nz6E0TuB52MthhOTZLqsCx0JCzutX5nvJ5zHaEayp/lN\nro0ke73/A8Gc39+eRrBdN7QbUjZTJXMttRZDyOaZfuTXRRmqgVO+rDdI9rCz\nwIj0qFSmNWYC3bw59i9eksm15aJbgbFMjDJ1PAJWZl96gAX3ZtFIklF2JZqd\nHhn0oamOe++qfVMg6qYd779oWTF9cP3Ckju+/uvcUek0bjeTbpHtMu9BfFPA\nVd5pXjBX1C+GnX5yAsQ6B053WcQUxWen94biw7bEu6nrUGlHXZAG7w7D6fll\nkT2ymFwJ5bENKYjTgctA1JP50/TUm+KnalANMnb/NnmM7Y199whKFlZb8rSA\nuF6aCvmSJKdTiTqAWrRPSbm0RGE2jj8QLzdkFTAIgzkm2U+xJQVrQx/oe6fT\n7cOp1unearL/3F5PSvTG+tTNHzaKkQ9lgr5Vf887A1H9eEyyj+AyPR67RNdQ\nb7J/7ieINnWHlcNF2SzJIrBNd94E4oJHanpoU0qRKa2K/TAvAH0/3FXAVJ0n\n5FdfcSjrpxmA8qXFUCoKc0ZR12oljB2XzDc8icGonjb7wS2YYmFF6oggEedg\nob0m\r\n=ale+\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDD9hvzL8KWCqH5Z1wgZ7S2IKheu8WI4gc9SeThHPeItwIhAOytiMNONjJvzM3toN1EhItif63gehFNjPmQjypt9901"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.64_1540153263913_0.8115200323659382"},"_hasShrinkwrap":false},"0.1.65":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.65","license":"MIT","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"apollo-server-core":"^2.1.0","apollo-server-module-graphiql":"^1.4.0","aws-serverless-express":"^3.3.5","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.0","graphql":"^0.13.2","graphql-iso-date":"^3.6.1","graphql-playground-html":"^1.6.4","graphql-tag":"^2.10.0","graphql-tools":"^3.1.1","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.3.0","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.12","super-graphiql-express":"0.0.2","typedi":"^0.8.0","typeorm":"^0.2.8","uuid":"^3.3.2","wtfnode":"^0.7.3"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.0","@types/graphql":"^0.13.4","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^7.2.8","@types/lodash":"^4.14.117","@types/ms":"^0.7.30","@types/node":"^9.6.35","@types/uuid":"^3.4.4","@types/wtfnode":"^0.5.0","apollo-server-lambda":"^2.1.0","aws-sdk":"^2.339.0","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","shortid":"^2.2.13","ts-node":"^7.0.1","tslint":"^5.11.0","tslint-config-airbnb":"^5.11.0","typescript":"^2.9.2"},"globalDependencies":{"@types/del":"^3.0.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/merge-stream":"^1.1.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2"},"gitHead":"86a71df07f5dc70348b299939f5dfa3cee756f54","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.65","_npmVersion":"6.4.1","_nodeVersion":"10.12.0","_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"dist":{"integrity":"sha512-IGnxbwMViPsLrB4pLjHPfWg4SZhnOmNqlTAKX8iJlLwK16/VXHNdRcSP8JdkJLjtaI7sdqGVgPyJMRvU+RbKsA==","shasum":"d5b8b16abdf080f183c29f45cdcb1debd1fa9585","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.65.tgz","fileCount":356,"unpackedSize":1017601,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb0vHiCRA9TVsSAnZWagAAjgoQAKHMxQskrKX7B71/86xJ\nxnZ5r7hnudszIpTbcwTal+sF2DnchcEmuIRclYPbgE7QPIDuLtke8dImtpRC\n6hNB2tOlkrFUBdPwO8n11Ejs35VnpstKPWhBIFGQ8NE/vgZjHqx0drHFWEku\nluYtW1AI4ei63YE+7Z524KudolUlwQOm++5PUt5g79awtQYw0OMn1kBFafPP\nZ3i4xra+aqLx3z3fRv8OLnOjr72FjsT7HD+HbmbLxjeEJmS/TXMClE8yXDhF\nLwGqmVQozKcOD/DQrNBNu1tm6Go+CbPs5h8GD2Wxn4MfiR/Nda67tsYNkjNA\nNATaaGsheDFgJDOWIIbuBvVc3vW3DnoE6gvSBmZg4Ts0TzqXDydupVU6SXg2\nreDIYJ3u4W+Ek09o7ZTcw+bQV0ycDmJWxjsWIrvSh15IReYF6JjZH0PwPNH5\nbxE9j50Wdz31E6gFcp+zmK8jlNi6N8A0j1CN+/ZSMjJenz/bFFbajKdKbZ02\nayK0Bmb7vCRNFkOFjPdhzbic20kOS9SGtPzCO/pB8Ezc1QZmj8/9prDP2nWR\nUjGZx1yOm45gkyFMlygvYk53MCWMHi1aepDFIhuRqLgCG/c6DwwgVPiA8bVB\nO00eJi/goBcJYfhyVv94VVfBXbUc9tAmAclSoTkOQW+J7Z3e7KedA7afuA+B\nkwHw\r\n=1WQx\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBqGLptckVR8V8X6xwb78IvTCupyJpKKEYCPyJ3eOHqkAiEAg4w9cVnrm1lGnJ3xgUUp0xyemOpokfKfAdEnda9IsmE="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.65_1540551137768_0.4409085432069759"},"_hasShrinkwrap":false},"0.1.66":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.66","license":"MIT","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"apollo-server-core":"^2.1.0","apollo-server-module-graphiql":"^1.4.0","aws-serverless-express":"^3.3.5","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.0","graphql":"^0.13.2","graphql-iso-date":"^3.6.1","graphql-playground-html":"^1.6.4","graphql-tag":"^2.10.0","graphql-tools":"^3.1.1","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.3.0","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.12","super-graphiql-express":"0.0.2","typedi":"^0.8.0","typeorm":"^0.2.8","uuid":"^3.3.2","wtfnode":"^0.7.3"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.0","@types/graphql":"^0.13.4","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^7.2.8","@types/lodash":"^4.14.117","@types/ms":"^0.7.30","@types/node":"^9.6.35","@types/uuid":"^3.4.4","@types/wtfnode":"^0.5.0","apollo-server-lambda":"^2.1.0","aws-sdk":"^2.339.0","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","shortid":"^2.2.13","ts-node":"^7.0.1","tslint":"^5.11.0","tslint-config-airbnb":"^5.11.0","typescript":"^2.9.2"},"globalDependencies":{"@types/del":"^3.0.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/merge-stream":"^1.1.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2"},"gitHead":"4f6f4eee44f0b4ae11554a8664dbafa79bcc6a06","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.66","_npmVersion":"6.4.1","_nodeVersion":"10.13.0","_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"dist":{"integrity":"sha512-cz74neE6W6/KtUfnwONo9pbEu1hxfZvk6aVYEUSssg4ddjwvoUiOyKdjMsFrd7gpozfMZAfu9cWHoOi+5nR4Mg==","shasum":"27a190385d6c668022eac5c6a162a5ffeed5ed9e","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.66.tgz","fileCount":356,"unpackedSize":1018086,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb7ocNCRA9TVsSAnZWagAAx9QP/3fOP77G+9aw8utiHE9x\nraaUAa8klq5iD/oPNvw+DNSSW94qavjAvqMahBVyycUdhRVercuxat0wgrGn\n/ZCglsbUV5SmOobVohvgzdu/3Sgj/F/z5txfVaLWOr2pCJhtr502Ph5KrK+d\nsDymmRoEVqRc1YWrC+6nWAczj3ZVocGp2i2FzIyBYo1nCLuhcoHRUZIJcWd2\nC29E67ZKcPA5z9VBm7uYNhTXWqpYf+2pd/agiptPG4P2EiFRSKIrhKIICb3h\nGJEE87lFlQnhFQpTNOmqI4vu4C08rf272GVVXKX5Bh11i4L58x3hefNtrrEv\nqRjOMtPqW7Lc3620UT0tXJ4nG2gpSWOOARE1Lh8m2g0KtWJZ/JYI++lrshFt\nAHIDdrw1+Z94JGtp6iZ4IZ40AzoS5EuxvOYa1uAJ9A0lmzpwxrM8X6UvWoEu\nSwttLlIshdCLHd6BI7vjaRizvmWmj7xMAZL09nmM96K43F1aOqPJ7Jcv1ZrU\nKh4uT4SlBRwFRuO18kIbgePT5Xd659tZK97x9iUXwX7TCv0aAUIlvxW8QNVE\nNIEsJuZajqEH2Y8nOLA19y79YkHWaePCw2rVZn6GqPydAwON+Brm0B97bFbT\nEmxBy009aDc1WBnuoAhj5qlukA2WIbjvAwRnR9ZcWXrQ+mngKDIJo/amd6+h\na3Qv\r\n=zfCQ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCXD8LCEyOMzaVPCci36dUeb/S1GtlgPh7fGwvilsgm5AIgYm1JbQzU0ezanNu/jgNQKI+1+HsD6sbsUA2T1p5hJEY="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.66_1542358796135_0.6834504165969872"},"_hasShrinkwrap":false},"0.1.67":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.67","license":"MIT","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"apollo-server-core":"^2.2.2","apollo-server-module-graphiql":"^1.4.0","aws-serverless-express":"^3.3.5","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.0","graphql":"^0.13.2","graphql-iso-date":"^3.6.1","graphql-playground-html":"^1.6.5","graphql-tag":"^2.10.0","graphql-tools":"^3.1.1","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.4.0","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.12","super-graphiql-express":"0.0.2","typedi":"^0.8.0","typeorm":"^0.2.9","uuid":"^3.3.2","wtfnode":"^0.7.3"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.0","@types/graphql":"^0.13.4","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^7.2.8","@types/lodash":"^4.14.118","@types/ms":"^0.7.30","@types/node":"^10.12.9","@types/uuid":"^3.4.4","@types/wtfnode":"^0.5.0","apollo-server-lambda":"^2.2.2","aws-sdk":"^2.358.0","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^7.0.1","tslint":"^5.11.0","tslint-config-airbnb":"^5.11.1","typescript":"^3.1.6"},"globalDependencies":{"@types/del":"^3.0.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/merge-stream":"^1.1.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2"},"gitHead":"e33966a76f8c9800ed1663771a4b105af73b9cb6","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.67","_npmVersion":"6.4.1","_nodeVersion":"10.13.0","_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"dist":{"integrity":"sha512-Mp0CioMVf27wO5VyLeyxBDWfcKmM4SUA0a1dx+RfeRHa+YFR9B4BjIP/oK9LkeWZUhCmchPEBbonUOQNFWy50Q==","shasum":"43db83e34fe41b1411e4ff2d3829e332df2e88aa","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.67.tgz","fileCount":356,"unpackedSize":1021558,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb8G8nCRA9TVsSAnZWagAAB6AP/2/XTq6icKiYm7U5KIkl\nvWuLEYqHhWsKxPh/Rq59Gj3BPJo/7KtzwZgWody+r8jBBexIrEF9Rq1RxFTf\nDDN7O+RgQd38EMMT6wpap4xSqZl+BTUI4iCyiJEQnxrT88gi6/kL5XTVuj1P\ntjUW32xtSoAectP2AwLDT/+2BLd7dYC84esbgDudo145E6pYvOfIjnB4NxZN\ns/o5Gvks3T/jHEGLX8ZDhmY2PvppsideJoN5SEIEOYPU8AGsjgUBT3x4QJgb\nToYaEwEU1jSFYWz+6Sz4dPNp7r6fEuC/HHltUEAFLbMsbpVbYZL1BPk33wl5\n9DLZOG1+v2v+YHfxxcKiTxS39XlWnYoPEukTpMaezcH09fVCiLh5yaCFvxEd\nE/DUgEot0huHlqT1/e1OoxcuIyLmIfnBWZYfT/j71jItzxe1Sp7W3JcQluwT\neDwiP14XCXA1T9kEKXkI1bWv9Jrgvzs3Bpu47PL5TrRFoXlbEueCAT0mwCOt\nSfSUcHxfB8I1Zl8dB8Ywk7WNnd4q97SAcVDAeQ+P0sGUqUJc2kelaaYg1qeb\nyHHhffe2LLrd0nYyFIwAGMVyI/sQUaP/7+iGROiRJleWoMY11X9VlxfJCPch\nxgqb4BhMNzVXLqvrseH/YeOGGmDu+8P3EwsoJRt+SZ8l5VbYygkG50qrR3kU\noglB\r\n=9r2m\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC+SHK32ahTlqaIrI9O7FOIlfFjQgFqRqXCpbp3uCsqGgIhAMYAiOFfj+5D/suObW+q0cAXwdDEcacP5Lx2Ltz7hQs7"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.67_1542483750858_0.08719383865394481"},"_hasShrinkwrap":false},"0.1.68":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.68","license":"MIT","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"apollo-server-core":"^2.2.2","apollo-server-module-graphiql":"^1.4.0","aws-serverless-express":"^3.3.5","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.0","graphql":"^0.13.2","graphql-iso-date":"^3.6.1","graphql-playground-html":"^1.6.5","graphql-tag":"^2.10.0","graphql-tools":"^3.1.1","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.4.0","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.12","super-graphiql-express":"0.0.2","typedi":"^0.8.0","typeorm":"^0.2.9","uuid":"^3.3.2","wtfnode":"^0.7.3"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.0","@types/graphql":"^0.13.4","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^7.2.8","@types/lodash":"^4.14.118","@types/ms":"^0.7.30","@types/node":"^10.12.9","@types/uuid":"^3.4.4","@types/wtfnode":"^0.5.0","apollo-server-lambda":"^2.2.2","aws-sdk":"^2.358.0","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^7.0.1","tslint":"^5.11.0","tslint-config-airbnb":"^5.11.1","typescript":"^3.1.6"},"globalDependencies":{"@types/del":"^3.0.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/merge-stream":"^1.1.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2"},"gitHead":"3cd4c4ae7991b9a518082782cf4e59a5f5f111a0","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.68","_npmVersion":"6.4.1","_nodeVersion":"10.13.0","_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"dist":{"integrity":"sha512-Hswspv1TMeev5aDkvdxvN9d+bA0eJ2Uc2/+5oNpoUmCJyKSV0ALp1diFj/Hoi+4/8essNFoKbSX/QC8Lu+pc5w==","shasum":"eb8fb196ae2f6ca2295485b8680e91284d83b40c","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.68.tgz","fileCount":356,"unpackedSize":1021138,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb8IC7CRA9TVsSAnZWagAA0jkP/3vAE1C4TpMjM2teSqS+\nz65ZnztG8y+gH5rvbhCoSqAY+OG6ICLKt8qTsBAFlPsxhhf8CgQCXLE62EB+\nCcpny5QUrGY/Pp49fu2lvrVEk8d91nGsKEGzsBHpfBBDsZup4VuVklj9gYw9\nZtESE4NmvywG3ejM6ldwE6q/ThrYoM3UsODNh+RduyBgzm276gUGRmh5eFKJ\nGRhBaGemNRSMU/xRtNbRZT4fA1YHi5b9hIkUUZEx9VMIVmurILOVHTYFYCyx\n9TDpkZqPZsU2V4kOU2U6areLUvUJCjYhxQNjYx9JEWzUF8ww52NTUubFwfRX\ndSXFbVQrY2VGBUnp6dTWGAbrV+b1kfFo2YzQ2gU2ywRR3b9r1p6RqdD4+Jx+\nPpIGY3djnLbuX81AzZC73fcjmW7XIhtIldwvI90wQdIvtISkJmSxn1k1X98k\nLGpWQex5w+FWlmzJ2g/G4kywq+c8vxTN8KtYyLuBUh48Po1pJf6n1VMLQ/qG\ngsW4zeFWPoCh/UG2uk5tW9d6bAwWjg5no8biGr2uTMc+b5nLbVmI88NOwyUO\n7LBYPFxSsXfOADFnRtFSSaPT+F8YIeZ5fSs8g8qOC3QCVadCPoUJZmPLXG/5\nofsGXIZdnft6Ow9b3XrtOHoQHIDBu1cIMtRgaDDoLY6tYZkxsssUO3r8bF2r\nPnN4\r\n=zCpg\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCh80uZmw8dsMOr3daNzfMGc7ZKsOXQZQswT3uxcECSSwIhAI9UN0DCkK6iH8V3MB6Ssv0I3Qu2Q0wARiDudBAb7Otf"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.68_1542488250896_0.0442240660623241"},"_hasShrinkwrap":false},"0.1.70":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.70","license":"MIT","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p . --fix","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"apollo-server-core":"^2.2.2","apollo-server-module-graphiql":"^1.4.0","aws-serverless-express":"^3.3.5","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.0","graphql":"^0.13.2","graphql-iso-date":"^3.6.1","graphql-playground-html":"^1.6.5","graphql-tag":"^2.10.0","graphql-tools":"^3.1.1","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.4.0","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.12","super-graphiql-express":"0.0.2","typedi":"^0.8.0","typeorm":"^0.2.9","uuid":"^3.3.2","wtfnode":"^0.7.3"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.0","@types/graphql":"^0.13.4","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^7.2.8","@types/lodash":"^4.14.118","@types/ms":"^0.7.30","@types/node":"^10.12.9","@types/uuid":"^3.4.4","@types/wtfnode":"^0.5.0","apollo-server-lambda":"^2.2.2","aws-sdk":"^2.358.0","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^7.0.1","tslint":"^5.11.0","tslint-config-airbnb":"^5.11.1","typescript":"^3.1.6"},"globalDependencies":{"@types/del":"^3.0.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/merge-stream":"^1.1.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2"},"gitHead":"6023f2d6882bdc5e9f2409a2641aa977d12d5994","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.70","_npmVersion":"6.4.1","_nodeVersion":"10.13.0","_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"dist":{"integrity":"sha512-a/tVtzHBH0/tkyrOjgyPTKge3/K3qRcRBS8/2LrO9XACyXy2n3LrTEi8y3nTLggwr2syOaU6z+ARtJbG891P+g==","shasum":"057c5f35b76ff176d0e781dd22a03a88b0eace60","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.70.tgz","fileCount":356,"unpackedSize":1027703,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcLclCCRA9TVsSAnZWagAAFd8P/0I2Jg53JvV974imjr+y\nAhfpitH0Q0m8Ez0UvMAX2Ns3fToDpTlvjtv16Dv9L0wRADsJ/sBdZ74fPssD\nR/5ZVAMITmPEGkEpt29ZztrO27XhR2gGTF+17PVUz04MRls/zbUI2TkwTIKW\n145bFEAQa8vVLuWdqS5kLMLrv01GSAMJWEzjCeZHdFEOs46aqL5llDoxjUGD\nLyAewP3CSCH5uG9lJ0L2og8BOaUKbkKI0ISS72/v36KKSOxcDGq6W1gOiTQy\naHMA/vOn17X1c+/a/kM722PS4qlyczC631KNIQhCQpqOdTzqrLbl2i6VQTvK\nRWf4z4FAGHu5KAVC6i4duppH/Ah5oA/YUwhUfmRSwgo05NhRSoAVlvn9SOth\nLAxbdQtyEhUzZhhB2Q2M8hKUIjz3/K2pDXIuRzaahj9+8hc38jCntMrTdFX9\n2CCh0m7jy/mmDoBvdtcTYDmJkx2Sx3lgWGE84euCHciHdWm5yJiCAHpKNQ+N\nhfqJxZF04IFbH42nXO7MM1B5U3A77P2kd4NzWeOBolHGqiMzz8jRlzQIi5X0\nx8UxOhldh4tUGSkhip1ofNdKuSSsC5SdYumfyYROMpLIx7anHHl3W7QgR7Il\n4DY/oROPsf9yh1QI3r4BvWVQ/TmgmH/IJbG4elzfkfXUOBK/Bph70LP2iHI4\n8WMv\r\n=zuBw\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC8HutVFhZkm6tBsQ4l3apkf5FJTPOG65Bes5GFy+tN3gIgX72xkUVXQ0p5MAwSuMfelLN58KjNRZhbDNblJ6UGxfs="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.70_1546504513867_0.4990777691438899"},"_hasShrinkwrap":false},"0.1.71":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.71","license":"MIT","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p . --fix","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"apollo-server-core":"^2.2.2","apollo-server-module-graphiql":"^1.4.0","aws-serverless-express":"^3.3.5","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.0","graphql":"^0.13.2","graphql-iso-date":"^3.6.1","graphql-playground-html":"^1.6.5","graphql-tag":"^2.10.0","graphql-tools":"^3.1.1","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.4.0","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.12","super-graphiql-express":"0.0.2","typedi":"^0.8.0","typeorm":"^0.2.9","uuid":"^3.3.2","wtfnode":"^0.7.3"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.0","@types/graphql":"^0.13.4","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^7.2.8","@types/lodash":"^4.14.118","@types/ms":"^0.7.30","@types/node":"^10.12.9","@types/uuid":"^3.4.4","@types/wtfnode":"^0.5.0","apollo-server-lambda":"^2.2.2","aws-sdk":"^2.358.0","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^7.0.1","tslint":"^5.11.0","tslint-config-airbnb":"^5.11.1","typescript":"^3.1.6"},"globalDependencies":{"@types/del":"^3.0.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/merge-stream":"^1.1.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":"es5"},"gitHead":"f99e641c51290292fa5b9a076d87f98fb367a9cd","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.71","_npmVersion":"6.5.0","_nodeVersion":"10.13.0","_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"dist":{"integrity":"sha512-irp7wiNQqb5nOCsH9OdZBEYeW8gcLrdR3cq+h5lmAZ6wqSl1Y6imuJi3uXjKZaZcafkKZkZorpXUJUaoyZ9h8Q==","shasum":"7047d98b75e2a7f6f83f3e7a826c7f789b1ddebf","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.71.tgz","fileCount":356,"unpackedSize":1030828,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcUAUYCRA9TVsSAnZWagAAEqkP/ixcSl7W6vKeetFj292/\n8vrcTyv2oO5BGdKMsqddxe/fRmyU6TDpSnLxftYtJVvwGXaU5CYrMYDqKh3s\nJ0natKEFwCQ37/jF5cDXWBQ1718pRo+re0oJJyFZZxILuhO7KqPPDzfJaoFJ\ncxP0ZNpeIvY8uPn+vtzHdQWRc0qY5Nr1/xKYvUHJkB3XLnPIFo9wzfEVeTni\nvMnMdBB67ie7MMyNbPUbGty6ZUieKJcXXkKBAkHZQ5D1V2ESoxkzyVLIbo8L\nKrKPf3+KkjCEp1Ipf73eJYJu2wJQpDmJH266jZx7eEl5IXV0NKEW/Tui5GK/\nWLpKEmsE/70K0Xwq0gXI0M98W3hkPqw6VUC7YhiMsu7kwLDiG/OUvU4yEToR\nrqjr9hxHCAu/pD4J+brl4eNrLOX53/FFQYXLcP1hWa1v74CkM8/ZKwQHa9s0\nJ6QLTRgnCH99pelBnQyMFrLRuPraU29QCfNVktBW5aT1C3u8qM2qIVpFe5My\nq21blZiwsM1PF7t4ySks9/HqzP0eLX0VbSmIJ0WjEQy1svzbvpnozTNJ4bLT\nNl9bQUP5pWCglP4QTxq+fzs7h7kFnTLyK85qNCuGk2uuPyjbaF1+WRdaOhig\nPPklY4Z1R8ua3U/nqIRyvFr4vNKFz0RSQn7PZpRusYqO623BU2L9s7/YeO7+\nPROh\r\n=kJ6H\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDZDInC+qHl/w2OKHfzouherCmHmWdhDeCx0iiTa0BT8AiAeVEVp8EFjEvIOiFPhQ4KBBVv++5MywgZd7G9VrQzdqQ=="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.71_1548748055702_0.26592165815753543"},"_hasShrinkwrap":false},"0.1.72":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.72","license":"MIT","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p . --fix","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","aws-serverless-express":"^3.3.5","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","graphql":"^0.13.2","graphql-iso-date":"^3.6.1","graphql-playground-html":"^1.6.13","graphql-tag":"^2.10.1","graphql-tools":"^3.1.1","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.5.0","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","super-graphiql-express":"0.0.2","typedi":"^0.8.0","typeorm":"^0.2.14","uuid":"^3.3.2","wtfnode":"^0.7.3"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^0.13.4","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^7.2.8","@types/lodash":"^4.14.122","@types/ms":"^0.7.30","@types/node":"^10.12.30","@types/uuid":"^3.4.4","@types/wtfnode":"^0.5.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.416.0","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^7.0.1","tslint":"^5.13.1","tslint-config-airbnb":"^5.11.1","typescript":"^3.3.3333"},"globalDependencies":{"@types/del":"^3.0.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/merge-stream":"^1.1.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":"es5"},"gitHead":"210d2fe637fbb731fb011243c61eb76258ab9707","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.72","_nodeVersion":"10.13.0","_npmVersion":"6.8.0","dist":{"integrity":"sha512-vhRZsEqCLbf0/AoPdWLGf9CgGdZb0WbrP7JVLR820RFpRXIuiEooCEWKHHNMwk/AbQMdwtL/Ll0QWPl7a+yX1g==","shasum":"4c52f28e519d5238cb9e6dc140c789599e14e3c9","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.72.tgz","fileCount":324,"unpackedSize":867104,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcgM2uCRA9TVsSAnZWagAAMlgQAIlC6nS6p4IWcQ5FLBN1\nVUFkQr2ZoqrNKRP1eMLsVnL6Bawkbd5HUMCuh6yAlPbEWHFUhZSEH3RKFwxf\nrzySGx+L0M+dab4bAsXpuHxGAliAtmJnLGyG0g7jQq/LaXTUVFGRFrMbRkpH\ncwCYRGHsAk+fWHn/57/igfigvsKSeuI/2HxA6zmOKpekg5bfLg+OSk6Wf6iN\nVwcokccMiBgsIdWwCXtwkcGtBlqAWib/dCeLVF1Cna1P5TV4Y5UkdppJj34e\nBNvRSooGphwR9iY3ibRGP6M4xNWacdPZZ+/UoC7PW7mYIKvOrYeRRTqg1mGO\ntMfCQImn7e2tL6hNyotyJfelWgacpLPjtfR9+T5VqdAQT1B7aOo9jQdjum7f\n1bLYs70DobaNl/43VOCDBbLJBQaDCT9TDHJ1Ribr4k5f5rarmYxY+k6TVW60\n1FbUSp+QeleyXmRGFheaUX5df3BeqbpltqN3r6cgoWZZ/hKveETTBuASziTq\n84UNyrEapbEthRJVgit4yPWTKM4J9rzhnxpesK4KKc0mVpIT3+XKDUCD7SyR\n4U0Lp/WpXEXXa9nNweVVUCrXkbKQccznZe1rbsHAgL03kOw0EGbEd9pcV5ga\ntfELmj+TLAy22PiwsQXGif1SNy1XItCnqkFBKG4VKqU4GMahkIr2VE0QhtFu\nisCV\r\n=9ipq\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDswt1EhjJap2HbpMNfGvt1vtZfU5j3I7ly0e+k774bPQIgdwqn27eke4rnV5g84YLA8qNX8Op7hYux1iMHWKqyhyQ="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.72_1551945133177_0.3175784068834753"},"_hasShrinkwrap":false},"0.1.73":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.73","license":"MIT","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p . --fix","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","aws-serverless-express":"^3.3.5","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","graphql":"^0.13.2","graphql-iso-date":"^3.6.1","graphql-playground-html":"^1.6.13","graphql-tag":"^2.10.1","graphql-tools":"^3.1.1","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.5.0","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","super-graphiql-express":"0.0.2","typedi":"^0.8.0","typeorm":"^0.2.14","uuid":"^3.3.2","wtfnode":"^0.7.3"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^0.13.4","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^7.2.8","@types/lodash":"^4.14.122","@types/ms":"^0.7.30","@types/node":"^10.12.30","@types/uuid":"^3.4.4","@types/wtfnode":"^0.5.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.416.0","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^7.0.1","tslint":"^5.13.1","tslint-config-airbnb":"^5.11.1","typescript":"^3.3.3333"},"globalDependencies":{"@types/del":"^3.0.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/merge-stream":"^1.1.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":"es5"},"gitHead":"7b45cff8d486c73d9bf70102f823d0750b201be8","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.73","_nodeVersion":"10.13.0","_npmVersion":"6.8.0","dist":{"integrity":"sha512-stRp6xbRS+Hna90JdruxCUWNjs/I3FjfES8LmLCTNtV1Q1ykYAor52I0rBNI5aBh3qfwiddvc5NrfirOs9SNJg==","shasum":"6517820700a87fe9f963475313b2759ed753e4f0","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.73.tgz","fileCount":324,"unpackedSize":867104,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcgNAvCRA9TVsSAnZWagAAHGYP/iW2/xyq9dDjefeZcuY4\n40xAqvty1v5z7GixM2PeBkngVLyaqrvG6+j3s8Miyf8SoPY8uI1Ml2jV39yq\noD55RCiuTZU+AWIJN5PjzqsndAAtJ4tCcaUktx4/Ooqaa4wWvE1f6j3JC3Eh\njWxzJxCQO3a19W+qIEtIviXGmw40Km4rIoSRs0U8z8ElcYN9ts53aL8piqrf\nSrwma5tT+ytM/k+Nssqn6pKiwXbeCNeNXvj6j8oalvgtdjjVC442/vuNoq3Q\ndB6Jnv5/WI7RINQTyD/4NYXE9ks/zbWIfmkoMpiJQbK4an8XeKpNPzIWaEiF\nu1TyaVNbE5TBuDV6rh9tmVIaQxuquySQddHgc2P84BAJLP51ZdYsquMFCEWy\nmyKJHdwXpmG+bIucpfmPiAmBoyseC9/Dgjq0gr5ZHSIacdZ0V75UsPVZ1uX5\nKC0sbbzUsq8xQ/LLY1EGQ7noPVytFJaTnX3rh4d748Y6RKX8Xup41YF7HZax\nrUbRIjYIZgyZXi5RKRLVUD4S1VZoJWO2ZzESZhtpWiXnK6Msjho2p3I/BIiz\nF+qq9BWqPP9gkq2Kl2fgPFmbe7nwChQsC/WsGbPeHCMoBJ3J5Ydt04uEM3tR\n+a87pGxBjoNWG5VNgP5Ywb6kcFEQyOdh3hzyKZu+TOGjGJevuhklgRBOn2X0\n8uzT\r\n=clnm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDyd1GbAEavnkS1JLa7UJlAmpR+nV7UqVMOUeavp0ZNkQIhALhfWFlrQjxhODgqgVBRFTRuEbAIXQLXYA6OAhEuFyIf"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.73_1551945774263_0.4602223914868431"},"_hasShrinkwrap":false},"0.1.74":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.74","license":"MIT","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p . --fix","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","aws-serverless-express":"^3.3.5","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","graphql":"^0.13.2","graphql-iso-date":"^3.6.1","graphql-playground-html":"^1.6.13","graphql-tag":"^2.10.1","graphql-tools":"^3.1.1","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.5.0","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","super-graphiql-express":"0.0.2","typedi":"^0.8.0","typeorm":"^0.2.14","uuid":"^3.3.2","wtfnode":"^0.7.3"},"devDependencies":{"@types/aws-serverless-express":"^2.1.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^0.13.4","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^7.2.8","@types/lodash":"^4.14.122","@types/ms":"^0.7.30","@types/node":"^10.12.30","@types/uuid":"^3.4.4","@types/wtfnode":"^0.5.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.416.0","serverless-s3-deploy":"^0.5.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^7.0.1","tslint":"^5.13.1","tslint-config-airbnb":"^5.11.1","typescript":"^3.3.1"},"globalDependencies":{"@types/del":"^3.0.1","@types/gulp":"^4.0.5","@types/gulp-install":"^0.6.31","@types/gulp-replace":"0.0.31","@types/gulp-shell":"0.0.31","@types/gulp-sourcemaps":"0.0.32","@types/merge-stream":"^1.1.0","del":"^3.0.0","gulp":"^3.9.1","gulp-install":"^1.1.0","gulp-replace":"^0.6.1","gulp-shell":"^0.6.5","gulp-sourcemaps":"^2.6.4","gulp-typescript":"^3.2.4","gulpclass":"^0.1.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":"es5"},"gitHead":"d4ba80a16fcbfe61dacbb09fa13911c73d019345","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.74","_nodeVersion":"10.13.0","_npmVersion":"6.8.0","dist":{"integrity":"sha512-4v636dulEdqsVlsM+UKdeUWjdFIASxrHBoG44zYEqRaVJbC8dLylVg2dnlOcjiIBa1NV2SaPq9AomhSerhK4Rg==","shasum":"f05de7aa9cd82ce28ac224389d883e6b09ffa334","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.74.tgz","fileCount":352,"unpackedSize":1023085,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcgNePCRA9TVsSAnZWagAAFmgP/jiYj3sVDf78tUt4CBFX\nDYLwKSix+zaH+oiIqpgr1Bm4hnyq6X2IC6V7VbUSi1VePbtW4FhmVrTi9iud\nbW7lhtfn0MzZPXAPrwEmvyqdzHpEn12uMHyfRuKvA7iGamgJSoxyRR4hZWKi\n/ulWLY/HVUtLOmM81HAk87xEnVNbbIQqz/FCQP3OEc4MswGN5dpsOioy6Xja\nYAw4Ap9URxk0P5Pfcw0kxYMTNZwmScI7MzsubK3CNazy/aH1ePBNpzB5rngc\nazWlWxCrYljRK35cW7i2b1zOYfviiphEZv3vuifB1T9E9qSJPouldB7S35qZ\nCl0/fsFCMfTB5TNu9f1vmSAXRF7wyL5dM7ruZf/y2LA+iCwsUfKGJQE6//og\n79MicYqlZg1GTNR2kgdyp5XgJKP60Mf14oKX6nIAWTFfdGn7P4ufWaVthaPP\nWi6egobA0chJ0CrwN+kTAaTX/fg5+2V54u1T9n8vEQlj0m93hSSWOdVecq+w\ndSvaPUcK2QCydveYHV6GWUpZWglInGFogxPaSNePSOSXim4b+0fklZbSNzMB\nLEHAX5f1WPiyMvXGgOK0ua47/gUnMWMdFknyg7EbynvQiXo46dHMGGZ+dZ2C\n065DKXcNVjHsYQ//u8PdRZ5V+B2yK9FXyMr6cte/YeEOyBmEguXdLA5ODFCB\n6i5t\r\n=gUcw\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCTxuqdQyIptVenibpoTHXFfy5+441Vl1XBFEiLNpbPAQIhAIlb5NfmnKfCNmdQjHsMwFf4HIWnWgpsXoG+3iCnCX2T"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.74_1551947662012_0.6050618780426962"},"_hasShrinkwrap":false},"0.1.75":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.75","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p . --fix","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","aws-serverless-express":"^3.3.5","body-parser":"^1.18.3","express":"^4.16.4","graphql":"^14.1.1","graphql-iso-date":"^3.6.1","graphql-tag":"^2.10.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.5.0","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","typedi":"^0.8.0","typeorm":"^0.2.14","uuid":"^3.3.2","wtfnode":"^0.8.0"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.0.7","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/lodash":"^4.14.122","@types/ms":"^0.7.30","@types/node":"^10.12.30","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.418.0","futil-js":"^1.55.1","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.13.1","tslint-config-airbnb":"^5.11.1","typescript":"^3.3.3333"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":"es5"},"gitHead":"facf7f3bb7a36b198de9aaef2d9220c4aa921c0d","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.75","_nodeVersion":"10.15.3","_npmVersion":"6.9.0","dist":{"integrity":"sha512-v89ZUdQ7HUsPJMAqW5QZK7oXnrl5SjaPSajPpVxofVBzb22dVQwjjUOXQZ2kZ6R62Ge0ABfw2oukyPV1POpmWQ==","shasum":"0ba4eaf583c332537cb90901e095e109d5a959ab","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.75.tgz","fileCount":352,"unpackedSize":1083130,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJchp52CRA9TVsSAnZWagAAmDoP/ifB4E6BdAqcEAdNU/vn\nUjWzKhe5PAT70VCATqXedFP6h0PsNIwjAR5U3ADDDcxQojRzVT9tvs1zj+Jb\nGW436roCJSvRIjlG6Jj9ejFyzE3CkNpQyqwmMhRDoVmLEIa77NOamJKEzQsF\nqPKk+gECAK56sxhnDe8Ukx3PF4pDqLiDErFdPBS4dFn24n30fwr9A4G9UaLI\n8Cr86xcTfZVv4hqBQJ34J4H95wS7R2mFvi8T8DCBEYHQO1mwnbaXuSrmnLpi\ngL6i2uh+EoonVPx6EXKxqzZohj5pOjGK0K9CyAlcEDVMHvxlEAqPkQjxwIUX\nI7BS+RTUhCMuIarp0t1eBP6a95Ge76EptLS0SHhAhzvj/+q2WRByKtVDmbn9\nU2lWMe8MiJD9eCGEhDbySrWm+9c+x8WZAo/2DfE/e7I6kGD5KZJiVT4NBeHO\nDSBca9Mz8FZSnvAcxez8eMIvCVxgWj9MEAUBNlu1kMvOdXVa4uxhipEmLuXc\nBM91rBD/AQH7/f0cmTvcW6h/oqGYs1AH86KfHOjjFqEx8GgGLjsCj4G9IDwu\nTYlVzV34XgEOuJhUkJLu8Lf1E6A30MIAOTvTePdwtVZgmU1OuDxq6M5Trsqm\n/DQ74RdtgvH1IOan0awGfH0ikfac86GM3gLmP00BJ5utO5ACAcVhwSflNlaC\nyEZK\r\n=ZKOl\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDuWSEYTy0cMhnBSXB2diysauZEv7yiTZkoPw1TYQoEgQIhAJHZELSRAC2wZ7FU1/ItYzOHy8SC9Whpv0BKH5C6AoBT"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.75_1552326261645_0.5122531213353869"},"_hasShrinkwrap":false},"0.1.76":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.76","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p . --fix","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","aws-serverless-express":"^3.3.5","body-parser":"^1.18.3","express":"^4.16.4","graphql":"^14.1.1","graphql-iso-date":"^3.6.1","graphql-tag":"^2.10.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.5.0","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","typedi":"^0.8.0","typeorm":"^0.2.14","uuid":"^3.3.2","wtfnode":"^0.8.0"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.0.7","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/lodash":"^4.14.122","@types/ms":"^0.7.30","@types/node":"^10.12.30","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.418.0","futil-js":"^1.55.1","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.13.1","tslint-config-airbnb":"^5.11.1","typescript":"^3.3.3333"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":"es5"},"gitHead":"c2d9d87a5f2b2c45decdfe1d084849a3a530ef8b","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.76","_nodeVersion":"10.15.3","_npmVersion":"6.9.0","dist":{"integrity":"sha512-KOK64aA4ihXn+tQ+b4Vn91hFaduGANOyFSEQq9LvoDKSeqvlH3avZFk7skyDolv9NRtO0dbB9kUxIHWlVuihWw==","shasum":"96a1edf479275b1f25898e3175e73a001e9fc285","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.76.tgz","fileCount":352,"unpackedSize":1083281,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJchqOlCRA9TVsSAnZWagAASEUP+wcN228xnpT0pT1xEnvg\nenRGWASdOKpVNlAxNkR/RoJdKilFfEd90yKO79AaEmDyU+92yAVks8vXO/Z4\nfKKrEEa3ChunQG2NRgOIfogOMJco6TgkY1n0Nt1zRLnR6by+ORYdhSCK6aST\nIOoZsteDXW7cCM/08fBaMzu9DfftvrMXiNj0GCXQOSm8/4urWC3UEZRSoNes\nF6tsow3jJRe/o3CU2EWihT/LTrULaYzYEJLtnC7X4QmeomZdPbJGlS0WtrVn\n76LULkwp6m6oNGR1W0kHbcu8v/yqbz9d1EguCRbITY3rcEHlYoskffWES3MF\nXI1//YTFl9R/rQ7BPVccDimi/hiKKL1gbdXOWtEZHsiDzBMfw6Qmf92JhI2X\nsn/pDxs6XgGj5otTUeeOZoSfVHPj8Phj82ivEr2VUW5KVONHHoWdOUcEgKg6\nZElVHpkbo5EV0woUjmhq9JKGAA/UtOs1TIn4o79BheQ3ntin/aiksJwOzVYl\nIg3xhdDgykPMv8bVG2B+/3bw270Z3GDuET0V87BnmeCZ4v14O+//b63Efqu3\ns93g+I1adEQLSs8ssPPePd+TjS24blI5o4919ZMoAlelMl3xoMxl/tZFyzrE\np/qhVB1UwXnDtKN1nYIj3kI3oc2Xjc432wNasCdaKzK92lqluhsTyEgNBwh6\nagOs\r\n=G2uq\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCztaAsqx3x/gHYB4UqR3HuNJiXQ9HgafzGcGQlMMCOUQIgOPbYvTOyQLLNbCVvB9WvvUAnc4Bq8JnUBI/mtc1GO84="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.76_1552327589053_0.12976168112682207"},"_hasShrinkwrap":false},"0.1.77":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.77","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p . --fix","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","aws-serverless-express":"^3.3.5","body-parser":"^1.18.3","express":"^4.16.4","graphql":"^14.1.1","graphql-iso-date":"^3.6.1","graphql-tag":"^2.10.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.5.0","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","typedi":"^0.8.0","typeorm":"^0.2.14","uuid":"^3.3.2","wtfnode":"^0.8.0"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.0.7","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/lodash":"^4.14.122","@types/ms":"^0.7.30","@types/node":"^10.12.30","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.418.0","futil-js":"^1.55.1","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.13.1","tslint-config-airbnb":"^5.11.1","typescript":"^3.3.3333"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":"es5"},"gitHead":"dd0cdd1d1fd7f61222b561557707fd427ddd1b29","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.77","_nodeVersion":"10.15.3","_npmVersion":"6.9.0","dist":{"integrity":"sha512-OLZxFMi08ApOF+/xwB6nA7JCjcK4LSLb0h3+hERNsmhrQdDVZ89v+4Of3JZb0mZaE4IuhSmN8IFHpwn1p7iiwg==","shasum":"641966be3065c6d1377faef63d1548f40df7dd83","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.77.tgz","fileCount":352,"unpackedSize":1083365,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJchqx2CRA9TVsSAnZWagAAHPcP/0RIJTwKltC+COTzd7eK\n4jdpSJlEc79hff776+16KnIXl8sjy7zrFJkmX9kN8cA9p8lwUGbKsRrCLDgG\nMnILE4AhdJJo9GAR/gC1+XhBSk1CkfHGEWLRWbOfB7VLFYSM8xCxeJ5RCK/x\niyLzWoZ7Oa+vXXfLAznwC3LHTk09YPyfd8nJe0Vhrt41fQcKbPtRY649jrZn\nWPTVNP6LP83lOI9wmymFZpoLFpPlR6WrCGIK9eIbP/IJXDBZj14X8WqM7oxG\nwFH1i+pCS3SlRxaA2SLNX+oByH3BJOS2RThIldku8VhhYclwG4rl1YGpwmsu\nPGu8KKNyVd3cEeXLlQBK+9QTeWO6hbCTnNeof/Ac2t/mFhKGbaQojvchWtjb\nvUMnOLK0hSOHLioJEpewYxYAEQ53T/ZUOSt1ONl8YIwSZSVXWyKzaBx5lvrB\n9Uz3XPpqo4ZBTbeEHWJSFREjrEX7QLyyAYPaK3rWFi2XIaestvaR3DpE9rPh\nidAqibUlhtoP8P2CJRDUGnCGXOE3vRgX1L1CqmNQyo3mYBQ2mJ/gifGZtE3B\n21VaaciVcwdasxCHj1l0BPoRIp9PmApYd9SkhAyyn0rlG79WW9WCCf6uQpx2\nn1BLiT/A4tBmA2a2gd6V4L+PGpWkXL3pl5pHYdG1ClL9fmP2CL1NMjprfcqL\niRTh\r\n=EnFl\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCu2JLr2+lIm7G/DYkpHuFei3QhyjK48SYB0nDs13Vv9AIge1Bw/SiAVyt4CELm1WjyyX4tk8pk9emu/HHenOkBDHQ="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.77_1552329845923_0.6854806368448407"},"_hasShrinkwrap":false},"0.1.78":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.78","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p . --fix","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","aws-serverless-express":"^3.3.5","body-parser":"^1.18.3","express":"^4.16.4","graphql":"^14.1.1","graphql-iso-date":"^3.6.1","graphql-tag":"^2.10.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.5.0","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","typedi":"^0.8.0","typeorm":"^0.2.14","uuid":"^3.3.2","wtfnode":"^0.8.0"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.0.7","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/lodash":"^4.14.122","@types/ms":"^0.7.30","@types/node":"^10.12.30","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.418.0","futil-js":"^1.55.1","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.13.1","tslint-config-airbnb":"^5.11.1","typescript":"^3.3.3333"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":"es5"},"gitHead":"9c43e54d79b7ed2b46bb2847ea3a29bc0a6ffc9d","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.78","_nodeVersion":"10.15.3","_npmVersion":"6.9.0","dist":{"integrity":"sha512-JomLS3UmmsGoi+dAV9CDWuiv5YyrdtkkLZvlO9xi3+cVLjHjsWcy8mz+mPhATzB95MiKHDVA1B9x2AT7z781Lg==","shasum":"4aafaef7306478104e1a055cd3179e2c9750b852","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.78.tgz","fileCount":264,"unpackedSize":774711,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJchrpCCRA9TVsSAnZWagAAHWwQAIpvhsJnkcUxSBJfHpgE\nWACYCWeJlKjjBdZVEVsG2eXvVeaLD136wTwndhK5pouKwoSxjnalCBqfiera\n4OE1fYXUPctmkCo/nXETJRiD+uVarlLK6XBgQuTi8Xds7rv3eeOb/sX/Rr91\nCjUdN3aHFY3/n3nkBvu5CXmVl3CHR/aO533BXXjimgH7oojV4C0nSRcYyhH6\nzdBFmo07RS8PAlc9jA5wATy8NinOKi8PoHmUXXrGomJHURH/91DBthmMFlU+\n8Dfo8i4Cp8X+84dh1XpWZmmwLc+nDugaojf5JfRlcDfrRgLfnlm741QySqbR\nmEgEPCgmUuqgLTiH8cMLtgqOyb6FgCmTQ86nwttsEtBbBSjFJIkjNgAqe7rs\nnJj3vHs03W2SmPlmDyC2wCEqD6BCYHed9wXAqocVIxXJoxdwcxwzjUW+pQXj\nl254hNZZ13ksgPYeoNvekeMnfL7QIns78oeCQSpdZh5z4lxCR+CkJbvvOVNa\neyK2KOxYazN4yHfJA094qyWuPDaHpOxO9qixFqjuz4MRJHQqmEAaL+8d1aDv\nDhBOVUAfbWhnQtvRLiYeYDu737WVGHWThRZqaoH6iD/wGwkl/N+GimjDXesr\nmBOvhnKSVGhX4RQXWe/ZgnJrSI75v5ORVN9r1y5NyA5+t9Zkvy+7tSvvdEuY\nTxAt\r\n=tvp5\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDdK0S9IF/OkAvbNyFkrhZQXbQCqzoOPBeYSlRmim04/AIgDZizlBw8Gv6lM7JK8muO/QAf1MSVKrK7Aate91lodX8="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.78_1552333377691_0.141077391971558"},"_hasShrinkwrap":false},"0.1.79":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.79","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p . --fix","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","aws-serverless-express":"^3.3.5","body-parser":"^1.18.3","express":"^4.16.4","graphql":"^14.1.1","graphql-iso-date":"^3.6.1","graphql-tag":"^2.10.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.5.0","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","typedi":"^0.8.0","typeorm":"^0.2.14","uuid":"^3.3.2","wtfnode":"^0.8.0"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.0.7","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/lodash":"^4.14.122","@types/ms":"^0.7.30","@types/node":"^10.12.30","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.418.0","futil-js":"^1.55.1","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.13.1","tslint-config-airbnb":"^5.11.1","typescript":"^3.3.3333"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":"es5"},"gitHead":"47d03385f490e4a8164ab1f3ade1721c7cc39373","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.79","_nodeVersion":"10.15.3","_npmVersion":"6.9.0","dist":{"integrity":"sha512-O1ApNySjQMBoZVoTWippNSNBBd1UsgGi2mXA3H+f1L0nHiw6TVFVpcct1nnFPQUMuh9dp46iLuyHJ0PmCaeydQ==","shasum":"d3064fc27c2cf75bfdf6b37fdd19a63db565e6bc","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.79.tgz","fileCount":264,"unpackedSize":776152,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJchu7bCRA9TVsSAnZWagAAJEIP/1/VqOrbeKRy0up+cPhQ\nlneag4DUMrSfOEFMcoyy4T7J6mxSEeGdQUuQL7DqwOR4DMftT8QUFUvI3AIu\nytkYd0VeCcZigt7J1rN7iHUjewr+QSmKKcUwfHtQSZYWw05e1xODaQz2G3dr\nVygXWlkx/Hmkva/lbEm45/EfIrBIQMNfpgzDlj39PkjiosIw3Zz0eLPjhPab\niFgtSp4gSOEV6DOcMNsjsDGhje6cK7vLiGpZASELUJlb/nIuv8FideLzAreS\nX7n9xmjhWdAktvPk3+Uo1dDxuPZzmyhGQXZaaR3qvWDO9tNYK/OYt0ZwRzsj\nKExTqKf9FdlJ/QdxWWj1RFMC4p8TYHtGCKsf6jW51doCL+d8GQkYwOoSXJtH\n80Mx7URIz/Jjd+v3ChoZzTK33fPSWUhy2VOz72JJyHj0Z16rt/Y+3uCnkMo4\nIDLW+23q8+BO61pxR4jA5x1/u5xKyNail6zGm7COB2RYiiBak9zCVQ7ydS7J\nKGntILYCiMSIIgdEJ7j2x6qJL1aAJTN7x2tCzoczCtk21tTIT11GlTxg84WT\n/OToICaFVRtM4VHaUaoj+QGBkTDLZqoWrPV3egVd9VEWhTcLfMGstTDzXRyc\ne+wU3om3JXs597irWlwEmWVu4R0Sqpy6zIm21x8Dpqs5l5vr0uMVXTTBY30O\nIZ1i\r\n=wKRm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFTAhe81UWgDcfSSl9rCj/nB6J0/McnPcXIuMfNI397wAiEAy6Q05G8B/wE6HIiwSHhGPRgKk2Z2w8L5K2fc1bX+/pY="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.79_1552346843272_0.6857093762516187"},"_hasShrinkwrap":false},"0.1.80":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.80","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p . --fix","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","graphql":"^14.1.1","graphql-iso-date":"^3.6.1","graphql-tag":"^2.10.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.5.0","koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","typedi":"^0.8.0","typeorm":"^0.2.14","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"body-parser":"^1.18.3","express":"^4.16.4","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.0.7","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.0","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.13.1","tslint-config-airbnb":"^5.11.1","typescript":"^3.3.3333"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":"es5"},"gitHead":"4525f2fae0c104b2736c03b6f60845104b73da03","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.80","_nodeVersion":"10.15.3","_npmVersion":"6.9.0","dist":{"integrity":"sha512-qP3ExVJQ66+0olJEfRdN9/3/vqC49AKXQc6/R/PPdw2yrE4biu9DkOT/LKPObdPnl9vHzI1sH1IWj+vM0pfnsw==","shasum":"728883fae60559ff00fd411fc3c01d55ffc5c27c","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.80.tgz","fileCount":255,"unpackedSize":778538,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJciE3gCRA9TVsSAnZWagAAcQgQAIo/v3x6A7If/MtXluRG\n9V3nXZ37s95oC8nTCYyxPHMEY1zHq1UZGtxuS2ZCYjko3p7FS4ktqQ+Q4TQB\nnEJfdd4AkKt8tTliwVImJ6KR4tthFwMgySFmeG/OxT7NjwJCSg3KqGgMVP5q\n9T5nicPOfXFz8WT7bxCGg0dKJixmwJK/Irz4EY+lNKa5i+mKiMNh7OLDYKmS\ngYBFcZVkGNkMA/aZWGhom+Ud2KTAjgqKGFZPIffYKLZjZ0lsY03yb5OzAvfR\nWXjS0ZzCih2G2CX8h7CHBG7yoG+lY88Oa0HyQKNd7Wmk3CMQRx548boz5f9e\nJlusMkYrBqw4vk0yULiFDsQgr+FSxr6j7lcER0096TkN4nY1XQ/qocrnTRl1\n+lV+G3i1DfzqH/2HFzll9d5bA6hhx/7XagYMg+qIVsmm6F+RA1aZylzdyRcN\nYE+qiLcj7eUScRR0b2FveAyvM1JN3IANDMUiB4XZUc0U5yGdzHTIG1mXL1gy\njhgOig7sEwipyYuCEKxMJtlo6FhprIr6GUySeUbhW7LS1Ifgk79wsh2xTkNt\noxZg+pt6SNBYohlmxbjbBgYIwx+r+f8uUX09nUjJMBmVBO4MxsEyk1PQgla/\n6o6rR3kb867yXBi1RkxuPsKnRgLJ2grRz+RGtDmv9GFAc+4djzvIdXceLRlg\nuk/+\r\n=HFlD\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFHBQXHKjHE5R/VOdj0wHL78qdj27kYt9MnqKVPHsovgAiEA0c1HuoTnLHQZH1ekuwS6LSfjWMFTmTpXMIjqqxNC0zA="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.80_1552436703360_0.25229400987294404"},"_hasShrinkwrap":false},"0.1.81":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.81","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p . --fix","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","graphql":"^14.1.1","graphql-iso-date":"^3.6.1","graphql-tag":"^2.10.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.5.0","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","typedi":"^0.8.0","typeorm":"^0.2.14","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","body-parser":"^1.18.3","express":"^4.16.4","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","raw-body":"^2.3.3"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.0.7","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.1","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","raw-body":"^2.3.3","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.14.0","tslint-config-airbnb":"^5.11.1","typescript":"^3.3.3333"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"2c6b56c6f2350324264e9e77aef574afe351ba20","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.81","_nodeVersion":"10.15.3","_npmVersion":"6.9.0","dist":{"integrity":"sha512-1yfcqljhoW3Rp19BAP9bm6lSd6XWjek5GNslu9PnVUm84JQpl57fgjTXgFTvWM+WdVWF5RTjyp1OHYNHOvs38A==","shasum":"a0cb650c30e7faf1896594840172104341fc7f41","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.81.tgz","fileCount":267,"unpackedSize":791146,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcicdBCRA9TVsSAnZWagAAu0cP/3ipo8GTMONEPBAskNOt\nFu8I7VhcvPkiO2qAkYWaiG0lDhOfSh+e+3O+znTBrugInJuc9gVmKfc/neop\nc6TLnhexRGga+PkmJuGDYBEbCZqAfLS9pPzjUZZxr+AoM8gRUbiFYDNxNJ4V\nf0IwQWwrGPBMsTxJkmkRc74B8oEwiPKNg7SAAxWWpdqNssd2c+DZwtbDQ4ED\nGRFFgA1pZtEOisWNxglByCTSQUN0Otz4MmLajsIA3mntKX+04hvKyDIRT6IK\nOoSu0lERQKWUz2dYu/qCxqADh+7dlBXKjlot2d4+JUiMvMx6VVQ+14FHguPa\nd+BD5n8mWNR9PmKIZCE6DDRuQgXdqYxBW1I0dYycEDLvEEylvjplw1WQ8G1R\n/aKk3LpR/OijhirWu3k15XZcwWRCOsiOkDxeHO+42wE9t73fzYE7DVyWytZ3\n9WsqCCqkEr9JCnGO5d6Eyd0P1/r6Qdha4WrKCZrKWkMEpSpZ2Lzemr34AS7I\nRTecKS4+Sg777Y+GUmhaEQFsMmtlnk380UYgwmgBVpDSeVclDTL9zgkoeykm\n5ZSwjeFqtQ94Xtle7buQG117XtVBEAmU7PFRoozZDMyL0da/uJ1t1u+lCjmd\ntdNcgiRl5IK7gukM8Vjp+GXzya9ZpMDvpBhh0NvXx4A2NKxFW0d4eRtU0MCV\ndPSX\r\n=7Ox5\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHtNmCYEudMhSvs4FKYXMLEmwTQRqMebW0ENgKUIobpEAiEAgkE2N+ip644laac/2y454GEzAefvlz+jZz5LmeiBi9A="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.81_1552533312720_0.36346118093740465"},"_hasShrinkwrap":false},"0.1.82":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.82","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p . --fix","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","graphql":"^14.1.1","graphql-iso-date":"^3.6.1","graphql-tag":"^2.10.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.5.0","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","typedi":"^0.8.0","typeorm":"^0.2.14","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","body-parser":"^1.18.3","express":"^4.16.4","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","raw-body":"^2.3.3"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.0.7","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.1","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","raw-body":"^2.3.3","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.14.0","tslint-config-airbnb":"^5.11.1","typescript":"^3.3.3333"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"fdb5f2c59d790952e01105f22c3af30a4561ef27","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.82","_nodeVersion":"10.15.3","_npmVersion":"6.9.0","dist":{"integrity":"sha512-w6a8OWzPKe6c+WQWQt4Q4MqihW3dHtJlIk0VMfsZoaY31rHpgD46WV+Y+ofA2yPEkXLosOOUXgZUZKZjV4ufkg==","shasum":"51491237b88f0657acc43258edb3ace1a5c0fcff","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.82.tgz","fileCount":267,"unpackedSize":791141,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcidL8CRA9TVsSAnZWagAAIOEP/jKhPa+rBoHTLGrQ+SDe\nGtWuqTdCH3Y6IlXw5/+ooQFrAIfupX0/ZhkvTi2sSjH1Q67iqdsyKE5/GMB9\nKFdYDZGS553sDzvu6/MSTG0FnqdzFRLDFPbcNsbfpIwnr2/CZ2qyh7VgUKQh\nb9NCgvKeqaEBBAAQ7ICqb9YhWkMTdqWuol1jGpR/PXXMkGUN3AaWM9r+0sHM\n+elntSIf+deflCFYUtkgxEqFMmMJbsLnwCQpAsLutuEVNrn7yEmN9HxGHuYR\nG0oAJOrzB2zcNRfQBuxQxAlwpmNxomSlNcoS+yY87YmX0/wvJB/3X1LGkAcd\ny6ScFugY2ojb/qKiduz8UpuAveUpy4lT924WcRqpqBATcC5y7mPfpfjoQ/wS\nOz4MOqRY9USvNttLT0xG6raPu9LJh1ljDt3CWv5U/jJO+Elr4DUdaLfw1Lyf\n2mGKPKYAh9mIkZy7s/oBU1o+11oET/cneG/TuIopzLIAw76VhhQUr5gnYAOv\nuiSXtA1PPuTxRyIQCvTibuTA5L+Lg6+ldLCx4pZT2dxRvwyS/iC/XkSXpNhY\nFjPM+Y66gbuS6XfNi/y6MMLWjwwgpYT9ywj3lY7KV3tFZRMPzlsQ8SCiQU75\nxzjEOyTdT0xrnboMhGE57fs4baJSp9OM4fNASs+b4ZwLhVcR7/A2OI5Gva0m\nvQzB\r\n=Z6/v\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFCs6GRPPUwpvp3k3bTscsE9BmjOS4X8VNvz07kh/wbaAiEAxYQf6hqdYuzkyTBdOQHhM7+ZqwTEn1dJKbTkst/VZ1I="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.82_1552536315394_0.09669844517621384"},"_hasShrinkwrap":false},"0.1.83":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.83","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p . --fix","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","graphql":"^14.1.1","graphql-iso-date":"^3.6.1","graphql-tag":"^2.10.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.5.0","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","typedi":"^0.8.0","typeorm":"^0.2.14","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","body-parser":"^1.18.3","express":"^4.16.4","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","raw-body":"^2.3.3"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.0.7","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.1","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","raw-body":"^2.3.3","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.14.0","tslint-config-airbnb":"^5.11.1","typescript":"^3.3.3333"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"65453fc0a14c0436dda647b6eca7c2c6687513ce","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.83","_nodeVersion":"10.15.3","_npmVersion":"6.9.0","dist":{"integrity":"sha512-W/qMlvre40hhTRt3lks945iCsiRkt6Cyucb2KEWC8ykVfjA6NhuM2OGyWyOVd5scp3+52f/tnDE1RH1gVLdQOw==","shasum":"b0dfaf3977e51f04b54f89d211ab1d48b35980b5","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.83.tgz","fileCount":267,"unpackedSize":789489,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcidvWCRA9TVsSAnZWagAAlFQP/jvK6TNSrrRVg4grymrV\nbYLasORrThxKFN6R5K4GdWa5IiXJV43cAHAzUx5lDxexQqzDx5ugNmY1xax1\nYMpSosdIF/GiIayVfJ9z7VLzmc6HE5Ti6CAv8ey91EUZb9s5GRJIXHaltH9t\nfGgUUcuPv5qXx+VRuc1CQbjCGIFMQRkKyJYYffsqRlFbW0wk4i7zBF+nmgII\nOc7amgQUnTKkhtDCqKZAIZGu2+kKPcWuKLk6IPP1LkRgg7Fv/iR9vNwJOlkZ\nnFhSUqPhWHs6aX9L0+eKdP9M9vcy8EoUaBWWfN/O68JJP7lmHmhEMz4CHl1l\njQyQfxyAW+19XkxWiBLizaf/R/Qa0/s2t24Ya/0WMMD9cIK/jI3jIyyGl3Xs\nJZQQkaqTTKYuHpefMGRBRcPKF/733wQhyxFRGtjej0mfWch4Fi9KC8jECJm6\nSGjbTvUcuqaCWKx6BDBYaTF7AzViaNWJlBR2d37GCQN43lpuuKmIduEl2Ak6\nkBRi58lVoekGTqISWZ8eAHb5cTPQS88oJzGJ4INbJ9FHT8s/926fsV91LTHc\nUsdfIvrBQcurk6/kntHp2pDTNEbyAliomVMnD3v8feEoaiSgyjtCAc2IbXFQ\nJrS4RZo9bC+Vclo4jOIVquERJ1FMQmnjHiVny8svufVRySQyTuoGpc871IVw\nAPVw\r\n=dvmq\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAi4FExyFfIFVSqXmyrPp6UOKa6zZ7XX4kP/yjFl7zN6AiEA3c/C6rrfu8ACn9dw6HqZAgCf9pVrIx6sp8slRKUoUEU="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.83_1552538581967_0.4527142099901138"},"_hasShrinkwrap":false},"0.1.84":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.84","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p . --fix","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","graphql":"^14.1.1","graphql-iso-date":"^3.6.1","graphql-tag":"^2.10.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.5.0","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","typedi":"^0.8.0","typeorm":"^0.2.15","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","body-parser":"^1.18.3","express":"^4.16.4","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","raw-body":"^2.3.3"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.0.7","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.1","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.421.0","aws-serverless-express":"^3.3.5","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","raw-body":"^2.3.3","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.14.0","tslint-config-airbnb":"^5.11.1","typescript":"^3.3.3333"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"a55864527ab7a27269f13cd081939ab17b7c2573","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.84","_nodeVersion":"10.15.3","_npmVersion":"6.9.0","dist":{"integrity":"sha512-w3YWADbxZbtUi2/DB5dcSdPHlkAE9fr1KsBhpJC6nPca6rRJlruuO1NabbtOjkYZ06QbTOif4lluSWE4eaczKA==","shasum":"f0516d92804ecc84621a8b64ac16885128376a7b","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.84.tgz","fileCount":267,"unpackedSize":783015,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcik3pCRA9TVsSAnZWagAA+NoP/RyAOhzqLZZ5j1EsOZLY\nUDWwfFp3zGYEdsCTmL4PveOBdxjNebDiAsX4SBhrcAjCfgQmlarBER7z+Y2D\nohkw5t5khPvd+uDNsVbIWCd2W79xHCxkFqtKuXpsbf2Go8hjdih5EtBAOqA5\nYoDiLwsLWcRR+Z8J9scyyGnIsvbv6UDTFyup4uPLj3vgz+Hrly/v2j9DqjKr\n/RMMyUdzwCp/3LCv7saFI0oStzGB8Fv52WiyvypLrG5Kfm5eghXfeOp3cPxC\nDvWk05e5C4E9GnfZonGwb8eEbDwq8b8/1ixczq5RxRqjvGlWhKR8m11bctV5\nROnCqUat2uhoZEYqTKzfXMJRJ2EkSIm7WCiM4Kse3SbIuQ9x90GaiA7p3R3O\no273THRWINQ+z1Mn3Ur8RpxlcWMZWg3mGkom3pnzlwarToc42kifpdsB2d4Y\nTH6W1cJ++u0I1agwzwzvQOdlVxSZ7BEFp09wBDfkMvGle1LOlZ2neFciJxkL\nUNZFwjRwr/qmyPcecQ5J7ljhv4J5r420Ev9AI52vWX3bT2jOd5/aa/rHsc0v\n5oMjtrc+vIMd+DEN7+jPrknoa9O6kkkW+AxXSFjdrb7L96F80/0EDzukmnYs\n4JcNpwT8iLPKFxdqQTaX2SXlpQH4UGsRhR6yd6yL8sYSgozr1CuHRCC7ZS+M\nTdEe\r\n=PdSR\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDedmgQf6SYlJXvNW75HU5NNuafZJb8F2ivp5z1YeUzcAIhANkd4n8QooqxmhuyBW2BoHhcui76/zcTZ+5k7pWxNYoL"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.84_1552567785224_0.041412701274394115"},"_hasShrinkwrap":false},"0.1.85":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.85","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p . --fix","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","graphql":"^14.1.1","graphql-iso-date":"^3.6.1","graphql-tag":"^2.10.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.5.0","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","typedi":"^0.8.0","typeorm":"^0.2.15","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","body-parser":"^1.18.3","express":"^4.16.4","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","raw-body":"^2.3.3"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.0.7","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.1","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.421.0","aws-serverless-express":"^3.3.5","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","raw-body":"^2.3.3","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.14.0","tslint-config-airbnb":"^5.11.1","typescript":"^3.3.3333"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"4d5ae9b91954b7ded395cfc7a609aa4cc2b7a32f","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.85","_nodeVersion":"10.15.3","_npmVersion":"6.9.0","dist":{"integrity":"sha512-A5wF1nmLf1ZhR6qSsWVdeHg6971CjMj8qTGYd1EYrTmKSOktTJIH9fl+6alb8LDNgNMx7litMHw0sv9w3lTbCQ==","shasum":"094e111dd26e19b080bc8573d01a44d2e97e1930","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.85.tgz","fileCount":267,"unpackedSize":783309,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcimjoCRA9TVsSAnZWagAA0ooP/j9rtzOTieao8RjSXdFK\n+hqFgGbAuYdboBvGlXXM+exB1KrkK39EXyQO793ti7l0xnWtYrLzzehnWFM+\nGJUvp6Eh78wVdTpFcdK1AS2IQ7CLsIFWXqGPoT3mgKlYtN0nAEfATiIad14z\nm9zYN1mEneLEpsDjQMRRugjap+lNwcrfaDrFkKZZ9Vh5q7KNCicShst8NSok\nQPS3ucHZrx0kxdBFmYGtkgukvMILdQ7tbma2gh5fe3M7v/xKuAce3YXS64gm\nJg3XKUL6L9QQxkKPE3uiviT6TmdP7r/oA0viq0siZNFSXBswO5DmOwL95gn4\nT9SmwKAbWpcCE9SFMCGG/gBS6rz8PX5zMRE0Gxo/WIsh39LMGms3tp3QQ+5p\n9hbWE1KkuGDaaHdciKF/CF/n/iJ9e6RdiYZyu1JkjKKnF3Ybj554z4BpKrJA\n3x8DCTX4BodPlY0VAJi3IHEwmM9QiG4+byehSYqTwXV60jMt/PMLlFpKimA6\nppF8sTqZzqHxDfJoPkGnS2dyfszvkUXZzxb2D2XnvpewFiM4EKZBZ8tBrTMn\nMvRple7BCxWNDgp2CpD85ILJbjr1LhdYw5OJdbpKJ4RFpM3GTnqGPOiqnwji\n7TnHdRiKfCu2rZzQqNsmx+KEmHToy8x1+SuYzfHRclw3DDwk5DuP7WgeYIyG\nnPsn\r\n=TITo\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEBcIXPMTSvP8qwg3zN6pf6BDp11iV7y+1igyc3QCm1pAiBLVwfaoW1lx/8e8K01Ri/4WYsgf4ao1+o+/vM4fqnTdw=="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.85_1552574695183_0.3720239486658974"},"_hasShrinkwrap":false},"0.1.86":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.86","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p . --fix","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","graphql":"^14.1.1","graphql-iso-date":"^3.6.1","graphql-tag":"^2.10.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.5.0","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","typedi":"^0.8.0","typeorm":"^0.2.15","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","body-parser":"^1.18.3","express":"^4.16.4","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","raw-body":"^2.3.3"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.0.7","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.1","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.422.0","aws-serverless-express":"^3.3.5","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","raw-body":"^2.3.3","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.14.0","tslint-config-airbnb":"^5.11.1","typescript":"^3.3.3333"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"8fd4594063254a18202484859695193b42f31c40","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.86","_nodeVersion":"10.15.3","_npmVersion":"6.9.0","dist":{"integrity":"sha512-aw+2+NF85+zNKvzgfNe83MsNBT7rJhx07DR2l6+AnFlZkczLXLjeUtaxmGNamtbqbiDeZlS0tLwPB5QmEakqdA==","shasum":"bf0b81a86ab0dd2b8ac6ea7f666fc6e231525f8a","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.86.tgz","fileCount":267,"unpackedSize":803174,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcjLK4CRA9TVsSAnZWagAA4IcP/2kXAUtoeyLsbV7E1lw3\nJDM1XRKm43nuzTQ//yWPt4xj6swNVaf0yxma7iIANjfF6O4zGJ618bcWiSVD\nBpWv2l298+ANrTXurgzKs6AqGi3nFZn8958bfUSo/Ry9oO2tMCV5gZtI78IX\nFilGtkkpzwoaK5zI5C3IEDuIoDwtxIiWeJkHZEyc+bFxByV/kGcDRXCRprs3\nY5ueGeAUroFw0Zp+a+5X0q80Fo8kjAJTxXzbWG7fe3ABPUr18WxiShPfRx68\nn8nFqwu62SkHra27iY8K4tnZmJL3kbjk9DXRmERTi4/OQ0igAyJ61rLoBc+C\nroEX/CvdXsFmZlul2B7E2e4WHy52DFMmlUTxXtZk96Zpb6CTde5MrLrlAMwF\nPwpd6YiFhcOL7eD5cZ2HKEV2Vxu0wO6IFdMQiuRosK8S2hxF9sp3A7dllZHF\nuOYL1RYyAQRDeHmeGmb/8fj4KSS1q9BoejfAXNJ6zgTxEzf1bG2GcXwecbu5\nRum/uqlxjfm932yqzUhXHv9SfrMXR0aSvY/7QjKTN1uEMBbzfc7BwVzJgptK\nhDpwcjsMsirPw791lNaqejkjctDFPUmNelUCvDEgzAWj7gOS2HiOfQQXbtgv\nlVJdjiriqUlzmw7EqBOXBFO8F98PsIfzXWwYLB3ZrbQBYx1xoGt0McZ6dUQ7\nHY9U\r\n=CBCJ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIANxRIY5caA8Osld/Vyzg9/0m0ySMzcIkXAi45rCpK8CAiEA2W41EUm8fAd8LM86IeY67CCRkkDhgiUP3oIm4ty5nrc="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.86_1552724663679_0.3967795029792771"},"_hasShrinkwrap":false},"0.1.87":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.87","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p . --fix","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","graphql":"^14.1.1","graphql-iso-date":"^3.6.1","graphql-tag":"^2.10.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.1","jsonwebtoken":"^8.5.0","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","body-parser":"^1.18.3","express":"^4.16.4","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","raw-body":"^2.3.3","typeorm":"^0.2.15"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.0.7","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.1","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.422.0","aws-serverless-express":"^3.3.5","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","raw-body":"^2.3.3","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.14.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.15","typescript":"^3.3.3333"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"4d392db4236885908289dbc068f27756ed9854a2","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.87","_nodeVersion":"10.15.3","_npmVersion":"6.9.0","dist":{"integrity":"sha512-LvHv8HdHM3Z5AA1GVr9MsBFAuoTOOvQuUyaL0YSMB6sOKqxDvl9ory4cGTqZ8+AoIdkEPwTGARcLYmuTt39j2A==","shasum":"20324bc9e67fb61bb6bb11ed9105e8ed1383c9a8","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.87.tgz","fileCount":264,"unpackedSize":828779,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcjpUECRA9TVsSAnZWagAA0FAP/jeHU45I90WErwCali+S\ngdRHnHA/hSU2dCEC7bECWQm0QHacapSdxn8JBoy5UWDpc84pp4nJe5iLeds1\nOkmKbstoqc3qp1Dk9xaZMwkuFK7jIFiiyPXRrc8+laJfl02BtC7KjUN7Au95\nPfJtiA3n2MLeLGFf867uNfBZdwqkkINa5vbmOiRetxMqsOvF/7XNoDWIpk2e\nT1hbRnyHFSCg3Y+65UJbmdEfmVbxL1H3eeruDKETVlR3BFr3r3t2q208iDMI\n3MsdrFdF83GdQ7Wq+eQL4PkCuAGe5BQ6cjLbB90urtIgah+7oyhuLk1N4coQ\nnDrDCiDxDtXI6WSGMFGau694Em8FHqIhrmSMh30cwB7WJPG1m5Ze4lxPryK4\nyeIKMw/Ci5/mskmHkhxEeeNix0kPUAFjghyHKN0z7mlqI2vgODtggyiQoAaC\nrHdwkZuknSKf420Eho0zLC4hX8RY+KI4+IZ3JpGYT8B5s+X1mvmOZZE+DNwr\niD2VYmHDgHA7DzHzrLcfzcHjlsZrLUTm0l0/F8w1yv6L0NWh7OhUfJiDoxbH\npYV47RXzvt3AR51cqtaYPILlygoxUNZeaKGWpSk8f3yqoKmt7kM9f+YCVn7F\nftjmjbEzFY4O8ENbuueJ5SwmLbH/d5HZW8TleDhMMZsKzmnRGe1cjMxenQCo\nlfif\r\n=pVPv\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIF4OWV9EGmwII/smGN+pXVGpt5h7/27uTnSHIZTrKll9AiEAt/Hf6yusrzWTx91kgzkjZf/1k34eUUxpemzPSBCU1AQ="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.87_1552848131364_0.24840326069854624"},"_hasShrinkwrap":false},"0.1.88":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.88","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.4","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","graphql":"^14.1.1","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.2","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","tsutils":"^3.9.1","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","body-parser":"^1.18.3","express":"^4.16.4","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","raw-body":"^2.3.3","typeorm":"^0.2.15"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.0.7","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.3","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.427.0","aws-serverless-express":"^3.3.5","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","raw-body":"^2.3.3","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.14.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.15","typescript":"^3.3.4000"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"431bdfd21a0b81ba3234888fa3e4403f6e85d065","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.88","_nodeVersion":"11.12.0","_npmVersion":"6.7.0","dist":{"integrity":"sha512-zU/8e0VF8StsSsiXHQdw7m8E6xCD28o39Q0v2b/M3N3A1qcsLwDaxexiQ5QQUsz+/Yn54nkWt+TaShHpk8v43w==","shasum":"19487d6e472e6ec2bd60ec15ea4eba734faccd8d","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.88.tgz","fileCount":285,"unpackedSize":920236,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcl0uRCRA9TVsSAnZWagAA+LYP/3RunyKijhx5x+YlEPCy\nkUOdDfuG9p06Eu0vhUoqQotLCsCh8ZxnKsguPzOJq/MlK98+m935p0j8Xar7\n8QPC+80y/Uqls4EnAuFXe71MZnZnfLPq//5DxRcW2XYaXRl3WzL0Ql++Z9aR\n0ISyGowQTPIjIZ5obbs2/ndzeshrj7W5gqgMdUrEqiUfBMe04wcY2Xrs84+4\nWIWJ79wxUFa6uJTRG0ZnJm2YZ4VOS9OPqHAHj5jIKQM3q3BqjE5TrX6Ykn/a\nWWtDie3lb83Al41OI0t3kSCVEdScctnxDwsLtngjGqbTLXpIhndsxPQMYkjb\n0/LQ1M/6eOtR137cPfxpo2Idpm3QMCQoBEG/lqDp3td8RUyo0D57LY7SmR+y\nUXIcoaAvnRc+yZkLir6cdROkR9isuUTGBC22Am9Mpm/auqKWnLa+MpAJcro7\nsayjWqzrVmNfe07tzzDH/LKOUtGqaPji116vC2tpjHYn7JJYal1nvldy+YYM\npWRbGBxLOpfJkKY8BlPDI3UJCrF7OQ0qNi2oceMjpaPiehWC7HuLTuKFeWz+\ncxqIgatekyGrxeVdOWE6ruI4DKKEsytwGiEDvxH4iSbUa9nw5AOYk73INIBu\nVgDF7UyxQfk6Xdoqc0h2PGVyRiSiDF2nK63NGuPgJAqyNhofW5Xl5HJc8015\nq+GL\r\n=kpoH\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBj640pv4CPOJvbtkX7m3EuvtCfUF4KpP6AmpM0NFek0AiEA4EBlALflqlzp4JxGjnY6NNDEjftUxcj6hK11KLjYvmE="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.88_1553419153052_0.7137773192176118"},"_hasShrinkwrap":false},"0.1.89":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.89","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.5","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","graphql":"^14.2.1","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","tsutils":"^3.10.0","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","body-parser":"^1.18.3","express":"^4.16.4","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","raw-body":"^2.3.3","typeorm":"^0.2.15"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.434.0","aws-serverless-express":"^3.3.6","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","raw-body":"^2.3.3","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.15.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.1"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"7ffc08c23c470f7c519120dea476960695ecc880","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.89","_nodeVersion":"11.12.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-iI5ByE0HManlochKUDZyGFnAkmBP9S0QxXwCA38a5xeyRDT8x8XTw8JSn5lLxB5JvuZfvLz/ipyJtm978nbZmw==","shasum":"910b844d7449c69bece7d1cb1bf22a7cd1808eca","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.89.tgz","fileCount":294,"unpackedSize":969517,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcpE38CRA9TVsSAnZWagAATUYP/34dHiCxtqTgNTHLCZSG\nairhoiKCYvoG15SE1RV3MtghvubBMp0PnCO5JdP+d6ABggdK4l01dRjsZyim\n66XkCWmONVY5ptTUx6LydmrDmHN9K45S2S+CQZ0tdeGw178xJJndbE2QThOG\nIWrWrSLtxnXmcXMG9gNtusSLKemED8m0GTT7sXFXeD+8E2TXcasSunNkabiV\nYAtDAX3Nf4iBMQVtVndSXbN1eFls6R79HlC7JYUhTW2iONMs/MeFtoLf6L1s\nriPBa7ExBc4G3CcTpTjn5v49LVoFqACUVoOvf5FMrvaFl3oGAwxnRpV2UHqG\nEaA8Ax8TPNcbakekKokRKjXMgB/0ScAjPRem1lrrkpDIUJR9Af7nx6iOuRwe\n+ypFNvu7zdt4zJRpqcqs93QQ4JjNWjpDRWBDxPRByOFPNrqDGyiiJvm0LaHl\nPkaO9UpvPP6KssivqO1z5jYJnBN55gCvcjs2g3+BgugiFo/x3fd9hHz8Zo3O\npthTTdaukbceq3wsaD3T5pjnao3kjUgyXo4bcMjWP8OszTkboxSQuLt9tEcu\nkC1jlAwlVzS0Eknsy4u19EZ7K3cSIt8A2lrOE87f34KI8p+q2ogtM9DsAhrA\nbv1/bCTJaUreR7IxBSu4BDUz905LRJN4xGKAavvfCvjA3dG9sxc5yknGd+zl\nsDvi\r\n=TwZh\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGyd6G8GxSiDyqmgUHCttoC61VbEcPCs5/4gStTXyDcJAiEA0auYZY20HkjriZcGsAv5500nwvmJZ8BkzCTfZcM9hZY="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.89_1554271739036_0.3497856468327958"},"_hasShrinkwrap":false},"0.1.90":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.90","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.5","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","graphql":"^14.2.1","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","tsutils":"^3.10.0","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","body-parser":"^1.18.3","express":"^4.16.4","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","raw-body":"^2.3.3","typeorm":"^0.2.15"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.437.0","aws-serverless-express":"^3.3.6","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","raw-body":"^2.3.3","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.15.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"94f5cce8ae68e01f8a6dd2124fbeb427557cd161","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.90","_nodeVersion":"11.12.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-8cSEe1yE/Hpg7dvT6PEmG+9GgSNHqklXaZk77bPjn0rY90ozfeY2JmN9n5aJf4JbtAqozg35JIRxuVRHDz98fQ==","shasum":"96379827dc2f126da279d0df2a826a7f979edd0c","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.90.tgz","fileCount":294,"unpackedSize":971679,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcqSc8CRA9TVsSAnZWagAA7O0P/1Xmor+dQBnFQH1Djnxq\nGjxO48A8T1MyQKGFIy3ygj1NVWYh2Ld3x30280W9pruaV/kAAkjm2Zuk/2Pu\nnPNe+Ntq1/XllnMjNQC8S/9kI8tMjl8ASkZDMDihDBnYl7A9uFYbZd05FLNa\nqtrGmyRLrmHj621VMljKHl3o/4BOuC3Tqt0PcN1apR+m3R3sYQSdcTHNHdj9\njK0CYSbM/mwXQu40IQ6xOOKlQwAXK0H32HHTdM0FxPogwBP3k/oD6WSBnxoJ\nVMlhlQ7OFjfaOnDCZgyveOXUWsvSKuC+GJmDD9hlYjZmwuu6TnzXYZJYdx8U\nfyoniezArDxiDfBmZedqobdHQmozxORp6mlSxsbAt9ot+BV2XZ9c9Xbe9g7w\nlWUETOoJHQkkVc/jcd6A7h2LTd9mjRlTEWOhfuj/5gku6em1mINXUIvp4FH/\nR8DddorbqvoqIudDVTMkMI4kEGpX6hepV4Zne1SVwBd8bCq7BaeiysJPu6zT\nJW+q60nHnChQKlI1pmdHsPOu/EudR5NW+LwVrupl1wAugHa5qfpHl0fZ0oy+\nVtGl7Nb4ohBpRFjkylM4G/HCTpcoiCZFxOs7vZJ00q1AxM220WjtXvSFgloW\ny+VKbOqRSIY2pbCdFcWNOKocDnrPKvV5qh2XoA3Ik9sJBDVI01DZjYLoG7Cn\nmw00\r\n=I3jG\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICoJ0zm5XOr6xF5bTM2BzrL7CI3lKRdzs5vJChx/PVXIAiAw/VeahMm4mM8RK2YQujhk2Zv0/v8YbReugyYaJDJ+8g=="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.90_1554589499514_0.43443612824183764"},"_hasShrinkwrap":false},"0.1.92":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.92","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.5","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","graphql":"^14.2.1","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","tsutils":"^3.10.0","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","body-parser":"^1.18.3","express":"^4.16.4","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","raw-body":"^2.3.3","typeorm":"^0.2.15"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.437.0","aws-serverless-express":"^3.3.6","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","raw-body":"^2.3.3","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.15.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"0b551aa856b8251f638a88fe8148cfff8b821c8c","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.92","_nodeVersion":"11.12.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-QrsNkj1afxm5Y6+IHKY1Ph696o/ZIiXum/AkXiYtyVVnp7t0ujcOUbXZ1Ddh8GqEfe7dWWcTFnCpyKrpcTFrUw==","shasum":"944e654864f8ef740195a7ab134b30a154e9230a","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.92.tgz","fileCount":294,"unpackedSize":971725,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcqTjHCRA9TVsSAnZWagAAuCkP/AsK4BfjoGkVzwGLS5+4\nsLbcYnJ3ctUyjNSfnCBc/r8lKI4x1DLhLKCjM/vNZOMrtyby9PHDQxg+ytk1\nkTbAwwgs4pqbjuM4GgfS6gbWODlIizOF2iaDlnUzbWpx+TbbCdGfN1w2MI8R\n32WQLyNtcMiLD61hViQxq4beUOHN+g1p55Ug95doCIYI3/7ZQ6hBf7a6kcpX\nSP3azk/uxY8e3GWvAvEYaHiL+M6WqPcrDBGvO93SIv4pqOD91Nth3xL4mZ3j\njXzwpYzcpKCvNABzolshTdEQmGfXOlb5akiCUDazYbGaCjQoPAFLEzKbAKbV\nyezVieyJCp+YY+rSHnX8aOD2GM54ZqZt0IuPR3E+H8mTHDVrdQisWSDz+rgZ\nKbGqXJcse/Mwgn0Ol2/B6nfX90+J4GE+NE00sG/1IoLm4Vic2ud3lKzfnbPm\nT4eO9binUyVwuFqCFXwCH5WdtyU6QC2f8QcA09kvXAzHLxed1tFwzcM1+8DK\nd13KBSj/n2T1seXOR3bpUfNnstAgee5VH0VVLlmr/C9VOPGPVFdawVML+nqv\nKX3ZNx8GxWXJYvlwM+uG8prrD9wtbsa+gEhuj+YqCB/APWM5e5OjhOGzKfxr\n6ENnT2hNHehmh40dMITb+ZZnHcmI6B3T2NsmQDP8ddDXPwigL1e555l4lO3Q\nrsbb\r\n=Kdt6\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD9c6syT4OMjQgiG6nok2pmqU7W7nluRrQlofFAv12avgIhAKySCJ4GWObTFexktlfNEdhxfrjjjToCRXzRf4BLY4FA"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.92_1554593990938_0.6876711521365981"},"_hasShrinkwrap":false},"0.1.93":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.93","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.5","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","graphql":"^14.2.1","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","tsutils":"^3.10.0","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","body-parser":"^1.18.3","express":"^4.16.4","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","raw-body":"^2.3.3","typeorm":"^0.2.15"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.437.0","aws-serverless-express":"^3.3.6","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","raw-body":"^2.3.3","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.15.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"ff272272a918899b7fd6a1c4ddf3a2e43a41524d","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.93","_nodeVersion":"11.12.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-v7bdJLzraVg9dW/8/ehP+5gbyqRBcgRqqIKJSbvcHHcIdzJlIfmZrRUS2sypSc8UqmxdjD5yM2EWnrvQID8fJw==","shasum":"f70545e7e743374dd2e585acdf7866e63d259119","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.93.tgz","fileCount":294,"unpackedSize":971969,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcqTniCRA9TVsSAnZWagAAhEAP/j0nuam/MgdlCE5MRn/U\nmzxkzYENUAho0bnU6+QdmPw7sif3zHfONO+p+MM7eKfsSjdCMZNIwbrWc1+P\n4VoICo7KrjKzw9LXzZyvtM5dSwkVgMroDI9AJgre5M79DN9bgDCCtdFV8G/7\neklQkNy8ZPnbcjOtTwcmEGinYN3fj2Oo1v0Qbm2MjzaOC75YUUWCSPgAHd0X\nCYjCrk3C/DUaIaoZpapYmjMvu1TZj1RAjKgGmvCD/CP1oNu2R3RhlVrAiH66\nrMQezS57GxKnC1oq9XOJF06VxMQBdaspzZ1lpARU9aEWbDbuQ6SnFwghTbSe\nRvRhyRGZPxirqkrARPTiaaU7Rf0InKMJggMF9E8+VTARNReX/kHksAxXGd/T\n7TxNCfaNOFZLt4dBbQX1qFgNqH6rgFpgpc8JUObh+UUuJdbciEXiwKxmZhT8\nHrfOAnzZgBoF7baCboOAs7/Nk2KaI8dwNwDZjUirJQae6Ena3+hIEhqn6KCC\n7QFf1bt2gtyJJm0r7lmAmK9J1yWvrJR5CeiJCloaprg5CsT07DNYN8/nc/yN\n3BKZn7+8zG4Ep6Ncfl4sDA6ncQqQ0RSFaQSIlfcQzTCCPNcD44i9mbMrJ3a+\nkgXx5sIfI6Pgn83Eq72N4Ry7fNwW9Qs/Jc5wGQ+ULWyFYuUBDljnOunEu4mB\nUMug\r\n=SmKb\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDK2De0w11PDDrfRo2TRdO3oilPyJQJa88Tvy4bkcK8iAiEAmuELLBVgb3M/HAcYJ3Ynt1fb3WBGr2sYKtRBxNeoUt0="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.93_1554594274067_0.6285908828797631"},"_hasShrinkwrap":false},"0.1.94":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.94","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.5","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","graphql":"^14.2.1","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","tsutils":"^3.10.0","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","body-parser":"^1.18.3","express":"^4.16.4","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","raw-body":"^2.3.3","typeorm":"^0.2.15"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.437.0","aws-serverless-express":"^3.3.6","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","raw-body":"^2.3.3","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.15.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"b325260d1a40347efd8261c77db1d3e72b568f8b","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.94","_nodeVersion":"11.12.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-Nfc9ZFrUBmWkUjAHv8iHb6iVXV/V0UqU4rDoH+ageM4UqGSyMOOOkfi2zl6OAZwgmypuWWHDe9iCWuue5kXGEw==","shasum":"4d777587a872bf8081254de69568b84e8a8a9c1f","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.94.tgz","fileCount":294,"unpackedSize":971984,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcqT0OCRA9TVsSAnZWagAASAAP/3nte+e08uwxO2WsI5U1\nQHafnEuf11F1BlbI0qJgOPeCshqWgOaI3vG1QKgGNOTxuWXPRVNcXlPmZ7Us\nymwJlu8845jWNkF8QCcEgupy28cHrD5unFA/ag7p+tmHXQVv1K/0dPtKXx20\nXExOfdjDXOCTlqJVpvcxSZs//V8SqKYxIvQ2ZxbjNIrtfORC+Z7IvK8DtAyy\nPw/RQT3lQyHrCz8o6oglT6vuha3TFGC9C0JkwLObppbch3q/lphww4ojfJdP\njsluuTFIFBWLpdlZTdeJUHIAUk35mrD75qYj/t9CLQWS1yd2ssyj4KAv8zCY\n74+Y/lz2RaS2UqFkI0CL8tLE94Q6AQ9vjmwkr5HoeOEMmuTgKkOTADfJsORi\nmlE/R3Lr0z3SbDf8SCchkWs5sCsxxGPIj69BerQDdQOK7Lp3giES9512JeZQ\n0Yfq/DUQ9J+inBgBkDFq0S6gKXhBxgZ/x7ZfeBuVDe4EllWwaL/ysEP3Vwlu\nMid+ED1B6o8jYGEWwNNvg0Z5xE2T5b+3InZ/DoMznRTgLL0K9tNJE0pQMqtI\n3veabzur8hJw689/2Kc6kiFk/m90NOaPqnqxOuJ7kijtfOwtueBPd+zEav5k\ncUxFoZAII/8/TqsLlCo27a8yZkpNC4Rxmz6ojXpsFRAOgCyZR3w0spX8cuuR\nxTh7\r\n=p+Bt\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGvEI4UpbzlJpLwetsByqjujHnatX4U5aiQyAFKsUadJAiEAyF4f9AHlhnfXepaxc6/fi6leZdqmJxkFtHdABvEPTx4="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.94_1554595085637_0.9527282808262059"},"_hasShrinkwrap":false},"0.1.95":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.95","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.5","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","graphql":"^14.2.1","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","tsutils":"^3.10.0","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","body-parser":"^1.18.3","express":"^4.16.4","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","raw-body":"^2.3.3","typeorm":"^0.2.15"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.437.0","aws-serverless-express":"^3.3.6","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","raw-body":"^2.3.3","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.15.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"d3c225f68c46117f78bb0d9d270441ebe85aebb9","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.95","_nodeVersion":"11.12.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-aDEYARCvKiHQBT4AGpowTSBdcT1B+eE15/iRZziDYBYxCXzSlW1g4rQKc+zZp5gHjjc7FR2KhfViSKOmOA/hBw==","shasum":"3cf8fcfdec938812143d322e995cbb6243a7c595","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.95.tgz","fileCount":294,"unpackedSize":972138,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcqUUXCRA9TVsSAnZWagAAVOwP/jsMamuDot223coYtk9q\n8uew9XxT3Bb1yTaju8xe3lo5uS3K1CsW4bkBxkS3eRvgykL16vyg/++pjA2O\nVG+egzpl8DFiFkY2Iy8WXv1FK+v8xqZpe6McYh8caN7zoxuBopbPq/gHrQLX\nmLOzrm1sJDbHW6b0LVA6OG1k+gZBOYgKlMCoi10G7A7VuF6XMcgLIEjOMhqM\n/O6mIBSWZVOe3fZfqUKvIhSTvGjB/HH26DocufTM2DmZpH00KDhKXHklooAC\n+0U9wr/rmTXwwCeZCm3VCF+HO0vI3c6k83ApQwftODYN9NPq1TCgUenav1Vq\nlIsOT+cEsagOelIlgIze0PQripucH4drFmFTzjQWxayUstZr9QPTEh5PdPBh\n1batBQNthHqguWVibNvv4YT5j3NCc1/b6W1twfnj10UMGKfzyv2bmP4iDvVU\neBXNt6UbsVjrdVZodFSGY48evzqkXU5NCaaH1ne/Jw34RMrg/ZXDHJ2DrQ1/\nvDn/OIXjAd4ayVMmeDRG3bKkGuIqoYYA62blKXd8VtNehwl6H/2bzPv1GjhF\nxHg1cdfb0dnncreEj4Bd/ba4GazbBgD/2pJvWFqW/Me08f3goRTHIgh8t5ke\n7VTSOaa/zFRrD1bYLmQvPwFdvu7uPW9T+Hy+XHDkTTNYDrXKNR11LMc+zg+A\nyty/\r\n=G4za\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGCYyA5mDq78w/Zy7Nxd8zPxkweQPFsdEKlq4oP8/cF+AiEA8eUidoosqIZij3SeRjpSZvQc0tMq1RjIAQJjXSvgb08="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.95_1554597142480_0.9601884260013653"},"_hasShrinkwrap":false},"0.1.96":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.96","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.5","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","graphql":"^14.2.1","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","tsutils":"^3.10.0","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","body-parser":"^1.18.3","express":"^4.16.4","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","raw-body":"^2.3.3","typeorm":"^0.2.15"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.437.0","aws-serverless-express":"^3.3.6","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","raw-body":"^2.3.3","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.15.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"27c347a7715a23a642ad93352222500954e46dde","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.96","_nodeVersion":"11.12.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-DOOuE3GkMrExNRCIBFXMpleWcEeLtLcPeRdI2VqXp3HB+R3JpTYcy39NsuLHQaRLWfACgAFWESCa/MaqMbQHZQ==","shasum":"ea7e5a6f3bc54c53d51a081d08161ad9f845bf3b","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.96.tgz","fileCount":297,"unpackedSize":976817,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcqgq6CRA9TVsSAnZWagAAo9UP/3mlbPNPc6y4PRYjdr5k\n2MLZGpqIhO+8NrsnH0ZOVOSU6i/Q0M0pNknfwbOHgMvwgYWYhzyWCxLgN2zh\nuvgYAAlCd09zuugPZt6rJ4SbTHvcPykmci90TnzmSy5sLsFumj/AJPC0sjqT\nDpdyL0/uXzW+mZGoUhs9bYKL3Y1b+jx9NU+yHzEGupdr/SjHtslsyJ47QABG\nPHNKHqMXyIo/MxgvSjFYzTOfJrRB4JtJXdBU3vLUVlPae2O4o9pE06Ho3O7s\nqqbZbKu8o5I/Au7WV98oNV3is3K4hxOBLwcMOjM2JoXig/QeWPMFjZB8brnP\nYzm7Yh2VSJXbkjtWMlmRDltlEevTvubcsPcPQ/O+WFVVdbV5pXgAaC6wFkk6\n6jI5ehdQTWTlV49lI8U4YhcgN/aa5OMjiTOJgT73cyf7La3V37kvR2l1z8Fj\nYJX10D30OqCLmH+MaWtjn1I7x9M+ZPaiu7v1v7qyI0Z5es6vKJetfvamAcXp\ny7M2YX403Rj5qcPF4dK6pbi4eMhncNe1/6zyA+/71DVB8tDIoHyNW9nzpa6u\nnxauuzGrF6Tdoc41HVcw8x3ljl0EsLn5nA6utYrD8R85ME8xCgRUAepZLsDM\n5aAbfERQFmsHw4bt8IkzIwfGyEtNQ3WUc5W3pi4J+GWf8neSDa/X4G7taw27\nJsaQ\r\n=cbN/\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDO62WOnWh4uxfOx7K1c7OMD7MiK8DBtQokFa1yqo8LXQIhAKZOVqaVr/RRb617b2Es672JpkPFt6WYYza7UV1Sykja"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.96_1554647737602_0.703819369613309"},"_hasShrinkwrap":false},"0.1.97":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.97","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.5","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","graphql":"^14.2.1","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","tsutils":"^3.10.0","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","body-parser":"^1.18.3","express":"^4.16.4","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","raw-body":"^2.3.3","typeorm":"^0.2.15"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.437.0","aws-serverless-express":"^3.3.6","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","raw-body":"^2.3.3","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.15.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"e9c595d808251744fe98a43c7b432ddb438bbff1","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.97","_nodeVersion":"11.12.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-zcmi1qXG0Gp0s1vXlvFtkuV9zo+Da/7MVSA12wpIWN/bXNFH4BXMc1b0cOgzkaGuPTRElj8c4ICPEx8c8rECnQ==","shasum":"c27678132269af6743a4e96a1bf69ba59151e23b","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.97.tgz","fileCount":300,"unpackedSize":977830,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcqljACRA9TVsSAnZWagAAV28P/j61juQHXnNw2WaBow6A\nuSaxJp6m5162/zkGAF5eQKJfcS+TL9QcpqhNcugrQBwlVyi575dkfSLDeAoA\nJyHawWv8qy4ixXwslyHrNDHzGII1CUAO2yP1UIxmrPKN1vFv7sNfViMMl+kI\nh09FGcUoa5ai8ZgAQajTwoigbtMbiaAeEGD3WUmVzUo8O7OvhlGc6hMFMjX0\ntUbe2IjI8BoLUOvDvZ8amBfmd5Cah+qSQf8PldV7TA/0z7LWgkjxlHR1mwIy\nIl1EgvO+tY5eX9mswh2dwiwJdxCbJJYuKB5rZCXcK69wA7+/l4h9DQCiDq0F\nUOona7JlmRikoU0fnzbviWEQm+stJmJu5EVUpv5MiU8PK/7r1d8dlfZYTIj6\nqvZsGTEzyOmZ6d47a6471SPyUwlsIONVNPQUyeZ7dIFxsC/SV8L1ZaLaLmnj\nu1ZDIgbtnzjf01hNE84k0e6NkkYZLjQJM8CsFodyT/ZSz0fpA7LVqxHaOG0E\nWihWwKXPFvIiCLUcRMkoc6h4nE6PjP39nxi17vld4OgIBhKvasXjcJOYitLT\nLAmtOk2TGEPhJqg73OZNJ3e2ZIyx2wxWZvgoB4Wfxl1ad2fO2UXLWPrtKsYP\nhdMVmquT4CrX2Op30yyzaZ9AIZIxbEM/yVyWFABPoUldZrV2pdBC8J+7Rh1F\nJsj9\r\n=lSWw\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQChMRLLc/S115ujxr/HzxYMteqrn4hgCNMFyriVk87kHwIhALJO+J0EBWbE/+vUCGGR3PNk8sbNR+/XCsbZrZb3mEOx"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.97_1554667711463_0.9344847803957783"},"_hasShrinkwrap":false},"0.1.98":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.98","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.5","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","graphql":"^14.2.1","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","tsutils":"^3.10.0","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","body-parser":"^1.18.3","express":"^4.16.4","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","raw-body":"^2.3.3","typeorm":"^0.2.15"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.437.0","aws-serverless-express":"^3.3.6","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","raw-body":"^2.3.3","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.15.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"c5596c399da2ac7500de2ca7543d9002af557275","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.98","_nodeVersion":"11.12.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-rwa0IwsS7H7whu95eSJFNzkLJME5/kXin/xmdUncfp64IZBlOJ3Zld5L3JHutUGpEA2TjrIae8V5+N1dEvkP7w==","shasum":"b9864aa1758f93725444d4aaeb83ff20af985a27","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.98.tgz","fileCount":300,"unpackedSize":978228,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcq+dqCRA9TVsSAnZWagAARjMQAIpNtYEw9aHU6IfgR4MP\nTnDbwVnPqTbASE39L2j0uVTVXwZx5B5Z5O/ZKq7l4IRnonDBdMfvysRckIYp\nz2fa3x6/nxN9YtUtgdymJYHnim+Vzkb3DU5Z29tgGUWRzVCVVkqoD3d7mb4F\nhnNabFFNxdY1iA6CTpsG5Q8riz1EjgmtAfNNJ32yQoM6AU3rrtXSgz2YFgaC\n5dY8+SGYmTbHv28vr6q8JIiCA57q/cF2KK4laZy5l81Nt2B+hwhUH/ewdTHB\nKohcHqoYZVAHrVwZgxn1J5kR2yVZeosxdEBwKy5+xyrCr4Y+AJtLvydTVSZi\nHPFWFsGRDuD2JxburhBrtl5ViqT1oWNVlUR1ZUQ8Pt6K3i76pUJq8nntpm9O\nxDG6XyPNzCW13PC8KaWmTLq4ZWfc7YyPnOiUBB6WPLnq5qzzWIgRRfUN04LH\nqXLlD/9+JOXSJwK6uuQIJd4ScHp8jXTE2fRczSzM//XcSPcxPoORlaCFDrjs\neDRVCU7MkJ/prabwowYZJCvxVdBwxYINBFf2Gmm9PcHJkou+zzXudn+KcfUO\nQqDXGKQHkmv5WhRxoXTJv7oNK6xBruOfGtC0BZuIW0igcFhKfKomprfFvlK2\nT0E91cCGM4Z6QaRvq+0qKOqMthDKveoVRl1OJJCPwdjVX/BZ07khOZHXCWLv\nDaLy\r\n=V/bl\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDPYqaWq21GM0/tHt2ogi/nAc9cLf2Jc1IrZSovCSSa0AIgHWfDFX5qOzqrXCqXFdMCezRYt9Cdpg9efsK3BYO0rnc="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.98_1554769769635_0.09428591740440795"},"_hasShrinkwrap":false},"0.1.99":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.99","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.5","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","graphql":"^14.2.1","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","tsutils":"^3.10.0","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","body-parser":"^1.18.3","express":"^4.16.4","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","raw-body":"^2.3.3","typeorm":"^0.2.15"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.437.0","aws-serverless-express":"^3.3.6","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","raw-body":"^2.3.3","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.15.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"2b079ca6c2f41314961bffe1fed11ae777d27598","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.99","_nodeVersion":"11.12.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-sVmET0ngOY3lj99twbA9d7j99fI+F/FU1Q4G9suE6NlIb6Kfbt1PU0IGtRKTB+rJvJ0w/m9Lv2+BgZRldFdiVA==","shasum":"2457f68056e49c480ced90495fe43b2026054af6","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.99.tgz","fileCount":300,"unpackedSize":978307,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcq+xtCRA9TVsSAnZWagAAsQIP/0YaV47Tugm6tT7Q1VNl\n+WNd8uu2s81IBx646QpzZjCgaG5VJ5qHdL+N0Y5m7WHdldoWYyyV63GDVKmm\nBpXjn+DFBaLRrPpjDboCXJWQF4ecuvdP/GjsI8sux1zTNY0efN5P60a8cN6i\ni3s/XP+WAK7hGLYo9VPIj9M3UoC0SybiOexrFZpFOFE8bUjsdQFFpGQ/hIPf\niEqiaJDWnarNVLgt7XCzwOFEifocr0XUQwLLvOMiv75pqDUgvPsZTfFxWV3Q\nqEYOVAghgZuDWhjjzk1d7NFAEP3w3G3v+cfOr3lL79P649I0wUNr3HsLy6HB\n+0+9u0InxR7Jf603EuDd/agH4xVC853fQFZqEqXbASATgSEztwUNy1Pg9WWj\nqNGYjssbP22F+h2uM+/pzdwUmcmE3YKv7YWG/6z25CmMoftYXAHzFUYSGXvq\ndvvTUT2LoZVDyfQ1LzB0SMPsOK64TBXCaEwRSFmgeGIIZvVOO+HmV8K8eXzj\n3VnRQqrczuaVw/40XVhWRVmyg7xV0B7pRJtuXMgPiCpuIkL3zwBdW8zOFtkQ\nT3q5falFWss20LTDCdgVMYTy4IcIlW5p50tDB1UKCADSx3fyYQvpyBmn19Ke\nS8POz6PJWxbe5UM0WsFwl8INa0nHNh4xuIOpaRhnkZW25VKvnXdWoanJNIiQ\n9FwK\r\n=Imb7\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICb7SDh5ywQ9v6fQLjKIf4E2N5E4RP839jFC8fL+H9koAiEAhhJe9TzRV6DsrG2OY90zQ9nST88Yy5TjR16fl8tunG8="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.99_1554771052819_0.9265885962567075"},"_hasShrinkwrap":false},"0.1.100":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.100","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.5","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","graphql":"^14.2.1","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","tsutils":"^3.10.0","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","body-parser":"^1.18.3","express":"^4.16.4","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","raw-body":"^2.3.3","typeorm":"^0.2.15"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.437.0","aws-serverless-express":"^3.3.6","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","raw-body":"^2.3.3","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.15.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"8a3f1e502cdc23105bc04a36d8fc66d5ca447244","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.100","_nodeVersion":"11.12.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-pxO3/05W8Ze33UybYMCGlrhB99ESJK9XyPP52u9DxG0Rq8Kmkm4C1wQsWD+XsR+SujHFiMftq1QQrRXlJ1UMsw==","shasum":"67b7e34c8fc38cccbe8d384273427612f0c00567","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.100.tgz","fileCount":303,"unpackedSize":985785,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcrGRyCRA9TVsSAnZWagAAQmsP/3jDPOD2H0YB83gpdcAW\n0qiVeOuErrSJCIBFeUmzGOg4VTiq+Ds5/MDJcuh+Re34Kg9Rr0V9yuiabRWx\nx5SyDql2jBCK+ewME5blc1MNumFFLTdcThPY61mO0JbixSV/ficNWPff4/wh\nNGNXzntkMPxS1rxVp0mU2WjSl7E+Bn+/HIG6KOxkzhZpoKj0edyUFD8AYwf3\nDpWyx/P82K4JTEiMxoBER2KXeiChYnCdeuyotFZtXfWwK8ke21V29T7Q6rmo\n9YZYqBpK5GzaP3Vzih53yAIZjYjim/VUh7p582ye5znmODIhp32H08hO+nn8\nV3VyNRGCGIXDAMfAv2OH0bcur7WIehhNs1lHjJ/G74H6JZdWReX+qvCzb4Pi\nUTZv9335kn+FN0HfX0Yd7EcnMRe/zKa7jLacOnveL1EXLzpFMhZXQ1vKo7Cn\nSykw4cV5iW9Z88TDW26t7pXa2I8Ap+rmvV5t75m7k2Y/hegfvFoWLDxc+QTg\n2om3GD/ZhX069Jadf5ZkJZHebwn/+HdWQUzWIuwoiu741U93mcC1O85gq02a\nkLYc0a7sYiRAZXGHM95NelOTVHKFnd5XUNwH2r3h9gFNkDvRzK2cXitUtmd0\nkfm8+yvhos9CVIHpjKk6hpYL5Cj2jQAJ6qstoob9wEwbQvBNsxEtBePCW8Qv\nkeXk\r\n=W/kb\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIG3Lk+0/E2dEl9usf3YtoirW9kbx7D88nOs+vYC16bcaAiAuYZKAH/XThVp24zz/p/fGR4VRtyqFx/1NfkWn2r7+WQ=="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.100_1554801777930_0.6460437416509393"},"_hasShrinkwrap":false},"0.1.101":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.101","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.5","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","graphql":"^14.2.1","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","tsutils":"^3.10.0","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","body-parser":"^1.18.3","express":"^4.16.4","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","raw-body":"^2.3.3","typeorm":"^0.2.15"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.437.0","aws-serverless-express":"^3.3.6","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","raw-body":"^2.3.3","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.15.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"d81b882674fa6ca5ece20d183c5621e589121666","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.101","_nodeVersion":"11.12.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-gFck361GRlyNZzqDSCJJwtR7Q61Qqbk65H2vQ0AStwDKsjicdc34sralnxuGb7ibBxbUxWbAZ3yiSS2amxi+Bw==","shasum":"988e81dcde303bc036c833ceb97aed9f9b60cffd","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.101.tgz","fileCount":303,"unpackedSize":985785,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcrGVxCRA9TVsSAnZWagAALq0P/iimPuxzPO2h2ktCHA7/\nRflSiW0ljgj/nbxfJiEcuMolPzInhGJJpRmgV524yzrIAJB9J3HPdTFd2uO+\nmzPT53pP5em8+gEPTpuJTm1QuPsAZT/gFbbazNR8xVTTFxKx2HnHL6M9RRNT\nnlpjCRhJdU76tL6HhnouI/YYvvo2KxLlvBuntZfr4T9lzuXdIrlFrpUzAFc3\nqKb3J1GZt0oLQ2Pof3Dy8M9PiPIX45wwABFibOz38w5Kfg9Sw5F8KjVH/89H\ndbMve9hOJexd+f/4cKVeFVUT62WOIvCgrfgXOV9N/d/aNQibtox/wurfRWsp\nYuVZrbEggHg6zuYMF4LSYZVJLeTyEbvcb+1SlLdWv/pj1YBgzi5yQwEn4p9V\nd9Apb9x0iJK9B8JIL4rem0M+bcWZK8tMlyeaiYWL4YZKzXsygNdGEItl+6ub\n054b/+wZbADzQAhX8UTljJvzqWsXM7bNbvFdSGQMyHe3TCDayG5S7Cy7uq5C\nEepL2M4blFDgPnpU2w0N6nOPHwgwGgx7txRigz9Evqlr27Uausbmt/o7mIgv\nykLqTYYWW4LIbRnUgAYrUEgqwrOyneZ53Aqv5b3GPWi+5FVAz3ILB1dRTo21\na4Uxy/tp3NWiEa8KhnLDcUw3lNljPSdoeMsYi9iZW86r+3atSoIxLI4Xktpx\nYlu6\r\n=Uguu\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDFxt/5ayIYCgdzU/vlTtknY2WPKFKzzsE1jOIsgAKZfAIgXC9+kc+KycSDBIWZGJyH/4xuPpL5kLfSHGkM8DvR9e8="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.101_1554802033015_0.9316833016887025"},"_hasShrinkwrap":false},"0.1.102":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.102","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.5","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","graphql":"^14.2.1","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","tsutils":"^3.10.0","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","body-parser":"^1.18.3","express":"^4.16.4","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","raw-body":"^2.3.3","typeorm":"^0.2.15"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.437.0","aws-serverless-express":"^3.3.6","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","raw-body":"^2.3.3","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.15.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"6c9c7fb39c9bce98bbc6ec4ab94d2d41a48256ed","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.102","_nodeVersion":"11.12.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-W5HOQ//tFGihoNayV2m9TBeXD0x4q1ZR2i6ScM5chHOVGXmPvWDb9Kg4KL9mpETqn8g4AzlvM+BhpB+K80cA7A==","shasum":"8e4a4a3631b23384e3d7d85228b0cc3eefb26604","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.102.tgz","fileCount":303,"unpackedSize":988657,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcrJPcCRA9TVsSAnZWagAAE4QQAJFzms7qOjyVD45TWfL/\nA1kciUHN/Euf5RxY9pv3DuMsdnRrkS7vyQKx/bl6kTKqsMaluM1EoPVKZ/Nt\nCAu4D2z06z9vQoK7x/gFYVpnVPNKEoU9PVYAQoNOeODclVsvvVPPzvWW9LzZ\nQK0MkFVmQkO27h5kfkYsKKPNg+PBsHaBx1dBfYv+6Cl0HT+Fmt/FcNbXZiA1\nLzKRgh6bnynq3+MjLqWnvs1JztuOBPyL+2Tjb3rsO50RkjZXNWxBeRCLX5YF\n0k4pWCB11nEsdAbOK0rdhpuGk8CGNPEBi1ZLwxmQEm+vJOJcPd1EQrNW5Dxl\nIODpe5zLA5iSGqclf7qQGLGHGDMwu2wXkGbTxv9Epb+Hiuh+BU4xll4W5ir4\nAEBOvR+GjTA6YKKqlYjfAcet4JEVkY/l1d4rLAIhpu7fhigARGGuWCYMcMDZ\nbGjVG6jyeoWT0toAlELl3S2DfLKl9E8u9SoTgHSRqOb5cCFdyUpI5unPN6xA\noqTQ1KD3u7a4zn40NgpdwnXi7xCnO7d4ssuxs4zbUdAhlvfOg757ysufxCS3\ndvRkGwn7FJ8lorsGlIje6+drxJ5zkXQil8eKjOvpmkOz1NDNPhyPyYGpnLG0\nQOwbe+Ui2TuSkmxO22rsU5tXrQRDn9gBN+MCPoF1toMP271hcuQT3M085QFD\n5ntw\r\n=iggt\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDbMSr+mez0hT5rPxHHETOvfO62m4ge5CapngL96tTVawIgbC7hIoWVJP4Mc1NnkdC8UPYMe2uNhYnBwYCsAGTuzis="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.102_1554813915541_0.7890252981149513"},"_hasShrinkwrap":false},"0.1.103":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.103","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.5","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","graphql":"^14.2.1","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","tsutils":"^3.10.0","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","body-parser":"^1.18.3","express":"^4.16.4","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","raw-body":"^2.3.3","typeorm":"^0.2.15"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.437.0","aws-serverless-express":"^3.3.6","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","raw-body":"^2.3.3","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.15.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"51c32c3fc2f6185b604ded4911a7c9b9ee58036e","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.103","_nodeVersion":"11.12.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-ihNalOFcxFFa8yEXcgpyHSZDEbGpHyGLwKpAj6NnuXCN6+DONza0EfJ1aatU2CslsIHPzF4CtcFEYBfqaCOKJg==","shasum":"57293e957594a689940aae54d8abfac34d1ca807","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.103.tgz","fileCount":306,"unpackedSize":1001163,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcrVdPCRA9TVsSAnZWagAAvl0P/32o1q6H0fzcdFFIiuvs\nJ04sjNyH7jl3zx5MMaVeiFw/eLEaUn0icVkFUhwV7su/J1pZE6NTpRnr1/VD\nxu77ziGwFSqlZxQIILmwrSrhjt/mnfBxkYSZ37UNXp3f+ZA2YKiEHOUQBrCk\nvXocYm8K1UND8J4k8UwGXKm4a9jlTWnKM4DqnHdh+dk7OwGOiMhIUiUduQir\nRFHArKkdEWJb7BfDxchIlNsbyP75tNN3dzQPqGa/eyGDiDVo71pYh2VYClE4\nHcKzR2I980qBjW8tdkWd+FyTF75WFkjYxiQOd4/RqtRC8xTeuYbWooQQE2J+\nuW/LFaHeCkRWj8+bmKe6dgJ/fbqbH6nPOA5Hn4NwjNX4Bt7zz0dQ6+q4kkIL\nMKIqGz3sFgjKrWt2D5s8jQVChZMdAiYoCxejUs39Lzc3dbWdbuLP0MIKyFay\nqkHYsgZd6kdTOn2NhECLQLQn0ib3nmlG+nuB858K3l0+WYbuFi+5qGz3gx9H\nt+LhbJgcdhVsxhUvbn5ASnfeIO1HO1yerQiTG/13uWNqDl6eN58mvqC4AzBC\nHjuOqXvlhrwjPSqtxTD18VnBqKaH/5i3fC/J4+j+ogPESfj1jdA3ERFAyDmm\nYdXZcSIIQpb0OKLKo3W2d7qGsbwjU5fDY35H2IsfNic0sllyorJIzWnxH4o+\nDDtS\r\n=Vv3K\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICyVd2SDH2VlNakaHd0yIXeLjHm8qthHB9SFKluc8ntcAiEAoSUrXjLF1oeGM82NmU0hoj9hxmTPTsocpeE5SuODvGQ="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.103_1554863950327_0.7382370908674907"},"_hasShrinkwrap":false},"0.1.104":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.104","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.5","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","graphql":"^14.2.1","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","tsutils":"^3.10.0","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","body-parser":"^1.18.3","express":"^4.16.4","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","raw-body":"^2.3.3","typeorm":"^0.2.15"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.437.0","aws-serverless-express":"^3.3.6","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","raw-body":"^2.3.3","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.15.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"ed6856ad4b461a8ea6fc7b43626fa7fe63a640a1","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.104","_nodeVersion":"11.12.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-XYfJBDtfko1uLbsCl4HBi1y8/RQJiXhCMct7GD7nV+f3KyxgGU8IVXoARjz9C+D8rt7gZm3b533lYKf+KdybmQ==","shasum":"3ca66056d045354179b4894a4dd68a447cd6c4af","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.104.tgz","fileCount":303,"unpackedSize":973302,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcra40CRA9TVsSAnZWagAAxZAP/0222T+tW6hTyMY1HsFp\no3ZEXlQE4mZcKctNsZW62knwwspbhqbucXc0Y1j7xxsR6BhZBGQDlkDqQwd1\nYog3r8K8mPFpqlUDp4y1PTDjRFusdSU1MSba5Fe7EdGRmnBnvg3KOQVu7DFp\n1rPFvVhdKD2vmsyUL21P/9A0fNcnwTja7cB319poNaVAjlfPNssVu6aYXZzr\n6Dg13bUNo2g9PLPlqDhQ0BafkQthzgocw17uyVYAFPm1q55NZRJKcaRsVtTR\n2ol88y22OhZgyMbtKNOR8tDlRimvElDuTBew53N98htMXEvd0TNPo6zQBymT\nNf3e7pXQrLIvT6dZl9nDiZ/JydQXEBe/UfC5em7J6ymhfG3ggLBB01PVTlNa\nBiVVipayoRRsWnwHTH+EBVw+fNmNOBoUixbIoTwnshW6Dd6fpFDurO93tDnz\nnBhjZUoyggCe8OddBYpF4+Td7XLQm9kMMAdDXScgAvPaWnkXnWbIfU0kr2O9\nLtLrZLCEIQosp09Be1KGDBbFwIhiaVh2/chgf0yeAKrGd1D+jqFBKoyBQsYe\nEodsIUHdwkRVyTcu2LYOWHoTrMQ8eMoa7qtm/9BuV9vT9aAVCzaExM77lau2\nReSRBxQr3p6tRHMDuC0LEokpsr5Y7MmD68bFTQ38+6a+DeFeyExeyN0Co3rd\nxFp+\r\n=1KXG\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC6ArBqM3YsUyN0atVsLQwNV3473aF8bmnf/3QJviRhUAIhAIGUt9Yt0RnWS5SPlyWfGcR9UqJb28EYoq7i6tG2WJu/"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.104_1554886195628_0.05804914424229257"},"_hasShrinkwrap":false},"0.1.105":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.105","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.5","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","graphql":"^14.2.1","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","tsutils":"^3.10.0","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","body-parser":"^1.18.3","express":"^4.16.4","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","raw-body":"^2.3.3","typeorm":"^0.2.15"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.437.0","aws-serverless-express":"^3.3.6","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","raw-body":"^2.3.3","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.15.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"9d6f17c8b68ec46f140c5370880777219f306f58","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.105","_nodeVersion":"11.12.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-czG1GeA3Ya+l/Zhjmnr5ARZtoIAHToWlHkLXCpvA1iqZuG1w/Q/74navVGsCRrQ8WMROBMjk9+HO1ZFs1vZBOw==","shasum":"870b2ed714f16d11df772eff2b83c153ef376399","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.105.tgz","fileCount":303,"unpackedSize":973399,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcrdD1CRA9TVsSAnZWagAAkH8QAJv2yHcmiavtAJM8Lncs\nSfxTAZih62MNjFRP13J0LYORYnaKK9j87BylSQBpRN1v4UptCu6lAKHq54Nj\nzFcynv0A+YK+nSyZPQs3jHT3JgH/EKzcFIoOjvHhorPmevPUqulu0Mo0h5EJ\nnT2sgnP49UJndnFs1GnaLi4cDeOkbkhv96tsQ5BV9RKjyXqGPSHxPf2ShJPk\nWRTFbO7ZWLhvHw89GB7ug2t/Jqf4ZIdRAtKHvMC11qnvduqQSwtzaFP89YZJ\nmwe+ObQGtzOjXfYApzJFIays/U2k93dc4bMl5FAsJOWNEN2gJ2A+C4IiJJST\ngM6+NBdq+iitGw7qsAzeQVQ6Ojek5cOU1TPTapr1rGnI/728AYXvIwHfZb2F\n94DjTbGJd8BmTTXoHtkfAXUaZDLepht6Hyd8ZqjDGYWXn+ZSboO+Al6qLj+t\nEPorGsFieodQoZMp0jmE2nCQCfVktMzcofKE7HHEZdGsExKWv9G7tnD12So9\nJ85QKo2pMqdMLqkUbzKgJgnXksURLodBy8xl5B8C1JxWA6Fo33WOd1KCOXWI\nZp1dZB5pHIXw33651zscoLUMLQ3nEEY3NLa/2CXfDBGEeo0Yk8f2d29zx8TY\nHs4TOfs+cWtzCLYCx3kDGVSiIU790Qva/UT53OtNDhVksq8V02mpuG9XiEFC\nzW+9\r\n=vMor\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC9Gxv/sGk399xMmzjix/0+uJztW9WpKBDbzZxKPbLfIQIgO4BLu3QbwieTwf9j1uAZIh6umKyis++v9vhQ+JL527o="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.105_1554895092928_0.9468443770887067"},"_hasShrinkwrap":false},"0.1.106":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.106","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.5","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","graphql":"^14.2.1","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","tsutils":"^3.10.0","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","body-parser":"^1.18.3","express":"^4.16.4","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","raw-body":"^2.3.3","typeorm":"^0.2.15"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.437.0","aws-serverless-express":"^3.3.6","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","raw-body":"^2.3.3","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.15.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"1a520de424bbe36201196be77d21c5c3bb4be288","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.106","_nodeVersion":"11.12.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-/lYtrdyHWCakhpst65stk9O5UF7GC8npN8BTExuJ55LzpBDzqogi2rkI7+C7OtUvaX6M4CerA1mZoqwaEM4n4g==","shasum":"c0738860aaf73d4e36539bf019479c557f28aa53","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.106.tgz","fileCount":303,"unpackedSize":973381,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcrfLYCRA9TVsSAnZWagAA2QkQAIslx8ihfKQKnFwGeNeK\naPOzGBMfmO95pzh2pxqgRpMQ8M+W9Mqm5g/Sry8b3A5kJAGzemLsVwqfID8p\nc4ecESwfnH395jlvNtNekvnQGCOUY5jLeKmNi25ez0t/1Z2tDJg9/RzCM3cn\nK2QnMm/9Rb0ryZVkWx28t4AxEnOUjji9jYjADa5sGYuu8yJPlO9r40ysPU2z\nqqnxGl9cbdLpMpiM3E7RzOKMZkdKQpo/G9IiMBzAnwcDzlfTn9U/i9Mmb6zD\nwxlScP7L98pnHuMPiLRtlKa+Q1cTC1uga2Kf6d+wQ3gRbvyyKEErqheJzikG\n2vLzoAfKWJJWPGkvQ5THJ42nvPLMtxdvHcEhSk+ONkNJaT1xOhQNJN+/ip2q\nCJlVUT/3OFa4BzPPm0mH+Yz8LyJfb6mzNMohrYnuNiYWQIzg+tcT9wMFcAYA\n0LDVrl8616MRWcW1VKkfNfB8Afbca3wk/89+FVeYOzbWc7ZluFKznXXAVnXE\ndMzPe3deosUDbmRFXW15CUiZzCkGUK/F5wckyO5zycO1zoxknoFVCyZm/taX\ne8G460LNr9lj1W1vMPUBOAo9BZQ5LTpXP8CF0/2FUjAkX1r1Ro7t64jySPRh\n2LwQ5QWIqP0mm1QrCIDYyB6QIeYiFqrrbjqm94HxnDbkImRwv2Ob7Xilvd/r\nX2Xi\r\n=3kEU\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBmX7J3ip2z26eQdWVaHvTRy85aoQVozOZkqzVZOcS0uAiAc69864fJ+Y657zsigsFvKc8P0J7kLgn5U+Qf0x93oig=="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.106_1554903767969_0.3206489444214702"},"_hasShrinkwrap":false},"0.1.107":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.107","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.5","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","graphql":"^14.2.1","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","tsutils":"^3.10.0","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","body-parser":"^1.18.3","express":"^4.16.4","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","raw-body":"^2.3.3","typeorm":"^0.2.15"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.437.0","aws-serverless-express":"^3.3.6","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","raw-body":"^2.3.3","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.15.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.3"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"91de5f66d152f574353cf7dd1e36d7a72dbcd0a0","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.107","_nodeVersion":"11.12.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-3ywCKagH6Aqv9ALO1VdfKpS7pmxytIBxf8zWW+8gkDj0gyw/ssyt6ZaQBST6hF0hQ/7ApBNOBzBEYkl4du51QQ==","shasum":"7634180bd741b9fc627a1585375e370856b2760f","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.107.tgz","fileCount":303,"unpackedSize":974387,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcrt/RCRA9TVsSAnZWagAADewP/1la/yE9Ed0fzrECrDQL\nUdmfko0deImBjkcYt2d1VgUhiuueol/JryE8PGRx6SVE6pKt8u4cMCuRzbBr\n1sfRRY+Z5PXt8/246ahzs4ekjn0fORWKtiDbwstsYnIv2e/+XNVtyvR2JDSL\nFcB+fhQ2kf9mRHcdC9tC1Ci6+narSyZU9pqUMMwf1yq7R7VpFS8RUXFzt+RW\nNmE34+rifLXjJgeTYChFSB00R5fYIui6mZaQwrN5umuI4BFPN/axoziX46v3\n4hD1VZj0gunVXt/ITgk46VhTix+o81++LbwCeP7Iy5qyLxK0IP4OqMiJeteP\nL9vUJ8F5Z2agjHOM1unzBKfEgRg8HqHo1RuISxyEky3DZaWXyxxem4QPQxwO\n4ydZOTaYsSyeGoisb1ClUnB/P7Dm6Z9PNsD7looDTLJ00EUGq8/5m0ObyCvW\nWOv48zYCptXFo/2526cF/33/JD+U5+jNVNst3L9h4tzjt5Sx8yaqEmH4EQOn\nfIoc9Cl4wQC0nclGWQYM5EutxMyhNs31F0sduhtYZoem1/oascl6xZsHt3Xl\nD9AdLYNDjFzlwiZGtwnQ4Deg7Kd5SrC+E5ujWomqzsfG6Hcb/44bG3HAk+nb\ntTX3y33sSRFg3ZSLakMYtYqdKReUZxVGKoudsp7bMawtmbxMw0lfO06j4lIs\neZhO\r\n=FHFb\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIH1QOobilCpJUgrU9Lvcju15+NjJUIWIK5tCkck9+jnyAiEAuwrlq30yzFk/rPKlm4Pk9sE+EuayeTbilr/lCffaSUI="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.107_1554964432879_0.4316500462933093"},"_hasShrinkwrap":false},"0.1.108":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.108","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.5","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","graphql":"^14.2.1","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","tsutils":"^3.10.0","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","body-parser":"^1.18.3","express":"^4.16.4","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","raw-body":"^2.3.3","typeorm":"^0.2.15"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.437.0","aws-serverless-express":"^3.3.6","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","raw-body":"^2.3.3","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.15.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.3"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"92b2998b291d27457f2eaebd24ccdc0f25a38f11","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.108","_nodeVersion":"11.12.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-1YjF06J4+ltJDkr+1WUlAyHLslxYPMY1txQT4bYY0guzpTPN27cOrMu/TaZtXrYO5Mp+UrEtWBLLErnC8P1W/w==","shasum":"06f44c00a55d443a773e90a066b70b05dafafc18","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.108.tgz","fileCount":303,"unpackedSize":974614,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcrxtLCRA9TVsSAnZWagAANgUP/RSQA4UubYcMJUTfEPAk\nBwjq/ZjtRqRrlOB18TDAfOHWfWtW40aDt3iq7VJxZt2HoicPmRNAEjgTYmLd\njQ1vYW86qWzzaQWLZx+S6ltiT+GmLCNU1/Z/eT7EHKtrnGAc306fnc5yCqE0\nSUgv2yrNQldfifoW7i8TxRf6ghzD9HF9bQXpO6GjxMpTzzyR+Hupg+g3YFst\nmjRcN/IXdrqRgxOJkn9zqpNhu+zvHlvhn3r+VTgxHAjorILLDIiR8sxEwMv6\nJE9KP0htvxMGLc381Tg+b90lMmLh1jVmL9tPDDgSoXy3nwKJFMShVpA3A/Yx\nZPHl1wacqrWmB3+XOaxwUIHPX6TCsra9TWQAi/lXr+3FQPmLs2Nb3i0g0Drq\nd22DUdiY20bBzQko/GVHhNPfTreq2tjxDWKEpOg9H2ghZOUbqiU3M6swQrXZ\nYL1AWmf/HGgGIVhyteYcsOJwh02Wv5tK3M8XT/JehtiDbwA/W2LIPknekg5j\nnsj0c4AE5cAjNpKUqpRT/QQnH+YP2Y70DBQ/or4qHTV36XKkr/vLWJAUMgjo\nqD2AABf6Uj5KCXkP65XEncDGik5DXXp4sOHEbcwkvvkBoU+QqwnfMvl+ki6P\nhlWGY0jPQNRQnEMyJzIZyjqPC+EuAXkX2XID4vJO+Q1XkK91HfyMb4EfR8eo\nsO9g\r\n=qna2\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCK6F7vCi6otjmzF1WbtUcddk4sbIZ5JdYqTVU8PMtrgQIgDZtqAPfsMDqVK0+RNCYwTvUq/4fwTBi6FqZQqz+4SGc="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.108_1554979658842_0.7050542176852559"},"_hasShrinkwrap":false},"0.1.109":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.109","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.5","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","graphql":"^14.2.1","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","tsutils":"^3.10.0","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","body-parser":"^1.18.3","express":"^4.16.4","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","raw-body":"^2.3.3","typeorm":"^0.2.15"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.437.0","aws-serverless-express":"^3.3.6","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","raw-body":"^2.3.3","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.15.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.3"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"41784062d28a251697e652ae02c13a16d8d6ebb0","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.109","_nodeVersion":"11.12.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-HzMl4zQ5oY6r/jdqubhC61n4idtmn6Wtu+STgZbaUNapdO1yEfuI+LEeuamH++jpMnkWRpUZOsUItrzMM/kZlw==","shasum":"214506a3122e9dac7f498a372a250e92be0b63a5","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.109.tgz","fileCount":303,"unpackedSize":975223,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcrytXCRA9TVsSAnZWagAAkeYP/2xLrXl4rm15kSrF4H9G\nYLh3zEB+a4eB6RFd5uJEbKvsgN49mLQMrSTnX463swAcnEgj15GqiKZjPdK7\nBuTp0J2rRxKC/MnejpIYUOs38I2xS63hs+06Eh3UJ46IcIbeciBWCIpR+NvA\n/ERFHC0OumO9BrsBRusPht2HTYQr2nkWLunIQb7VcILBxT3VSK0Wcasyvibv\nZOV6S1tyHQldhPXwyscPhsrCx49KvYbs2bjm7BtGcsn3cafJcyEt6u/V1QGA\nSz0rFW+mwhaTv063lfOCqqF0OGX7jxh1XGXS1BvhtrR2OJo1DRik0j4BDzFA\no1wvcqcEUf4zpNscHaAEaokD4MBWlvBe1RACEatRCpAW7bmDM2mAZObN7zWH\ng2kOUlnyy5G6RbHxa+PWZfr0vSSmi3CtkTWs9NJ6K1u6guTfekPVNVRJHsXM\nSxz3YzMKnapv+d3b5ceAcbCTXE0l8YUTDaMz+anF4Qv1Bzt/dJhCEbFaM5jF\nzHJXtqaDqKInBcwFGUu8eZwB9ewmUk6Lq564TNnGRviu7bSjoIu1MYgY+94O\nSaHV2kfuz9cO049TtaovLHEoPPRzurcqi3+gI5B9qyVyW5EK3kugbz7tbe80\nsGqdz8K3mKYkN/nrK+S3FkMiV0zTl8CAVC7gSRE1y1NtOhphr4C/Ceq0g8kL\n96wm\r\n=vVhU\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCk/C0zfPrjWnGbaw66fyXjRzagjYUbFLkwdo9wVvpUsQIgAcJz8x8bFEdYo7jcHT7bZCXEEXl67wjBE0VDOISrK/s="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.109_1554983767007_0.9566362153554162"},"_hasShrinkwrap":false},"0.1.110":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.110","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.5","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","graphql":"^14.2.1","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","tsutils":"^3.10.0","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","body-parser":"^1.18.3","express":"^4.16.4","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","raw-body":"^2.3.3","typeorm":"^0.2.15"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.437.0","aws-serverless-express":"^3.3.6","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","raw-body":"^2.3.3","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.15.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.3"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"9b57ea5cb9cf2579b1813bc027921112684e70e3","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.110","_nodeVersion":"11.12.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-njmdNDNMPTjtjR9Chxq3saNwPpLfA8uA/hn4S/CPi6Kby8zoG15uZwq5I80bhSRvZ1XSbD7IOwAeTSqsnoXaDg==","shasum":"4937546aa0d840d5f97b5ceb2c1b4c72646fc869","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.110.tgz","fileCount":303,"unpackedSize":975759,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcsCeXCRA9TVsSAnZWagAAj+MP/1lqnLJgKNJzSbEZCh6S\nElPTDoiNpO1lil1nBos+EJHB8ao/TU/CeAw6BTP4UXobNik/i/ouVe3dtGwH\nb2IUh4SCtXeiDo6Y+nYUWN1B0pyfSD6Aw2ru0x715QNti+BbJt3Ekw4S8HAs\nQKzF1GtcsoZa9v2lCqpYy2cMwD6WO+yoYL5/wIFHPVyEGWmeRsU51k/iCfe8\ngbLQXWCpoB/1Yb2CyvY63LRDhWwLSFvnXtPMs5UxQGEr90eS8lNnRRlPehOz\n40iIRcddi9OHbf82EILxair1LC16PagvgMoqmy2WgkvvAy25kyZCcHSA2i67\nWzCXl0FRUf8rypI/ZpmuIiHqWPPB59OSL6QDUSS/giBrtCgkeevUX0toWArL\n6C2x+yf+wxJDe4eZTLZ7ZvB0gIpiGeJt+U8zxKl6SeIVgK9ZG3cxQZNzKK1X\npUjsWsdJvhxr6Xdkh2lxdB7Z8DnwEsl5CbDEju3a0KaMjttjh8Id2+buTaIc\nxsu22aemWvP7cDei1pK01C4KJ6iBCghEirYT7pct7ZSrMDYVgW2+250Mtn0U\n+U42wKdXbXcLOECLpyeqPm9KhlN5HZrCsSesB1O2sTR81amfyZgxhv60V/Gk\nm83rKrLm9flXcZpDsxZHXQujz/uMC2hWMwxY3pv0NePKs5rkNokKNMMemA2O\necN0\r\n=9mCv\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIF4JHFS7RzbAAcdC3H/Xc63IehbnlF9W3flY9UA3eJx4AiArqJ3kXU3N9MnrjEBb73V/PZRst8fx/1fbRpdo5LM7HA=="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.110_1555048342734_0.583533404451714"},"_hasShrinkwrap":false},"0.1.111":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.111","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.5","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","graphql":"^14.2.1","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","tsutils":"^3.10.0","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","body-parser":"^1.18.3","express":"^4.16.4","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","raw-body":"^2.3.3","typeorm":"^0.2.15"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.437.0","aws-serverless-express":"^3.3.6","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","raw-body":"^2.3.3","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.15.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.3"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"e40ea91e47319b7f9caccf3e1b79f51336e9ff2d","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.111","_nodeVersion":"11.12.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-rzYeEjfWdMRasiiO2Gnu8cWedIrysvxEEEwj3SmfviFOS1Mv3zu4mZvxC0q0KRFhug97EmFCwNFr+gUlHIhE9Q==","shasum":"a7e2cf4d1305734665110b6d18b8a366ad345bb0","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.111.tgz","fileCount":303,"unpackedSize":975775,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcsD3sCRA9TVsSAnZWagAAJwQQAJSXnWsVo8jaiUae6tXg\nMsZH4CV5xh7pfa7Ew4faXK16cbg5hORRyAxpz9aLaKFnAOPNZu++1PuYREDF\nMc+dqkKFy4l+r78CsUiPPMmErxSd4qV/UwaFfbyzrTVxTMs+Pi+LOHgTbXfN\n6Fv04pbeH9P3saPT6XLEHkB7031Lvk8jtWwHbhrCOOMYm47/bUuCwJlHrTx1\naZaxGyBap0oH+T4TQMBzJB/M+rpzmm36a9z4984vwhcUjRrKx1YkeNAyzvpW\nViVkK7EaMEUCaygfOUeliPZSMdWkC/5XnGQrdsE5pe4apOsezwT6w+g70NU6\nnZKzE0b9rW52EPNlzDeZHfz6t8shV+z4UeiTbLiaofJpz+8uyh/MrV4EA4TM\ncCrFBFuFeHoB88O0OYL1+GSt8Hkm/q2fVjkYIu/1qnP08yj8AhNnx6SiidpE\nnkHJuKVydx7L8msTRyoK+C9oFV2Bii+smTRxgb0QjuLcNW7r1NhnNuIFd42R\ngXNCct2/K/pKFc552X2UlRqrH1o4G6QApbT+Ks8950CBsk0kesPYDHYDFpeI\nnHsJTx7UJWm1gtyZN6bfMj4R8IF0TWXI+ljZ4Xcs/BSkzr2xeU0vksReR8BA\n/ID4vlTv0scAazVqWYRfllL+pzwzphC24ez6Zk1ine2dYDpoyK22RQa+31Rh\n0p0V\r\n=O6Cj\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDlOgPizPSC3ny0pneglKxKVaOtu/ciTe4TzQ0yHvB7gQIhAJSweVgyKHwTxKKkRF2GPhcM+S3cUSVrqTXU8uvrD49B"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.111_1555054059941_0.40704038088493744"},"_hasShrinkwrap":false},"0.1.112":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.112","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.5","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","graphql":"^14.2.1","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","tsutils":"^3.10.0","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","body-parser":"^1.18.3","express":"^4.16.4","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","raw-body":"^2.3.3","typeorm":"^0.2.15"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.437.0","aws-serverless-express":"^3.3.6","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","raw-body":"^2.3.3","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.15.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.3"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"8240177299b6a06b6510b7d9ba1ed9250b002edd","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.112","_nodeVersion":"11.14.0","_npmVersion":"6.7.0","dist":{"integrity":"sha512-rWUgZVcH8NzPzH3s1jyixDZg2C3u/fzUzN/muXVkw4XHfz1U5AabG2jWM2fzf/mLgyj57AmJFm4voS2ZhVl+zw==","shasum":"d17d4df2a503e1f2f4c5db02712a86caf19dd18c","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.112.tgz","fileCount":303,"unpackedSize":979413,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcsHodCRA9TVsSAnZWagAA+7YP/15Y4Rrx2TbYyH5gKjCl\nR6+7witKvI3/ls61j1F8+wP+dUW6wqTWTSC2H/g7er/E1BM5Q26NucPwR37Z\ndzKhAaG/LGHZHt9ForX8e9ia87TeflHvrbAYnGxyQzBLQhCArZFRJKvtBcod\nfsvzo4uV8UX+15eFGi8gbP7HLevm1N3dIcMnZeSww7buH3Sk2FbCtD+uUXqf\ntdORwr8mP0JjylWgPbd2eBf01+StuhtxAjwN0ZhcMzRlq7iR/Dmr+tzUam9l\nTbK8YtI/cS+iQC9bW6QZiGAjPNefcq/IuFNgUPPW+P4SLfyMz+fTHeCKoMj0\ngkgpV++FVm63jCkIEq7pamHYOpbi2Do3NdT1wfZvYArsKK3Z1v57diKYk+xG\n+UzUvKONFotES8/A7v68+8wlBJf+gXDYJqazfLIt3ojLf6KZDCV6WSqiJ0OE\n1XbBYMsZpKgRwCZHq+uYF2SdYL51Gre7/Airg1K3YIfvMLSrfCyxY2wVNoVp\nsLUbH1XwVLNNQZlAHKy0EgW4GODvHl6gQUOmmOdCOpbltrR9d376KqzLRUQB\nel4PnRsXb5sfyai6F0GjELD2CfVGwaTFXrEH8y3Np1qKuN+0fY2M+aFhCqcS\nknBJqrcsARdr4ZKLMVbMmIXjJtmIc+n1luKsQbg8XkvYwQL/j8mUuDPbkUXv\nCrZF\r\n=/wEo\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFM3/ThfUcB9OuE518Jzg3QwuG70z6xa1I4MBC2x9kauAiBBnSfAYv/P5Su8vRULRVGPGjCtlwIDUTaCwYJte+WJtQ=="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.112_1555069468692_0.8433840200663567"},"_hasShrinkwrap":false},"0.1.113":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.113","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.5","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.12","graphql":"^14.2.1","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","tsutils":"^3.10.0","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","body-parser":"^1.18.3","express":"^4.16.4","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","raw-body":"^2.3.3","typeorm":"^0.2.15"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.437.0","aws-serverless-express":"^3.3.6","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","raw-body":"^2.3.3","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.15.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.3"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"c88e32d1b0a9a179256b855838ecdb3d4d550a4f","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.113","_nodeVersion":"11.14.0","_npmVersion":"6.7.0","dist":{"integrity":"sha512-ul5TOgREcnybzcRwFczXWRI1w5uWcTfWohZdEaZkj19f6MNLaAOXG9gQLYeGCm/y+fuFKjjrw0BGQ4/4YcGWSg==","shasum":"bb65b0c2d0878e1b3f7bfc43293171740790e20a","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.113.tgz","fileCount":288,"unpackedSize":943236,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcsKvgCRA9TVsSAnZWagAAP4cP/ikVm1m5dxJqpkRVZNR1\nkZi3O+SiRNybmn8q4VG+RZhPNnb9eXRhA3Bu6r5HZ3iVrAYB5dS0qHEudI9S\n1qu0bLUJ5XiAC83/Fl72hgQ6ixJsgiUc3a0+RdHw3aZG3sZJxcF/sMUWQW6N\nmL1iD/ORZgO/ItiqBJzoEr4uklx9S2FUSgIVxCQBQWmXjmNrOfrLEGcuNWwK\nJ9v1s7fZR3VCI5m6LgYE24nEAxpqikFvgLk7G0MYvCFg8t65FU4Px+S7DjHU\naAKfatPeJsZX64u8x+sfrLknNgB/TuQscvgfCgPSS/Yy2BNdka7cOmDy5UnH\nppt02PM1l809qqIFiB4WfKgnh3omeIeIv3e/XlPrL55dd3zfyQAjjc1wCE/6\nWI4iLSkRHutdbb5EbnkSom6RGZbXRIl+NSMZOSXazxwd00pO0h0U1D+aEFAV\nB6JHhsBa3KwAJrCheQJ2Hrz+tzP0FnTkPuatdWW5w6IFLMace2LN6D7Ix6i+\nrniqcz+7QqqcgO2FqJWdQlWZfQqwGN9bufPtmQCZ5wZgL1lbYOxDy1yxQ4tG\nnvp1xV9kS5Zua+ec4FQ7BQoyAj3pJQW6rcAKAbBn7uAHmETyC/nMRKPJhZT/\n4+wnLtcXg1tokIOwahjLhSXCTHSZIPqSGpwVtzIktmBxmhCkRwkvMAi6XKez\n+Tgh\r\n=XGQd\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDEU7mznM9xY85T5aW5m9X33gRneIkry36+qnx9ukyYPAIgXUTHwnaGTyuWOSn5Q6BIIjcoCC5PtoOk0WlVH/JXHpc="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.113_1555082207623_0.592485027632738"},"_hasShrinkwrap":false},"0.1.114":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.114","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.5","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.12","graphql":"^14.2.1","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","tsutils":"^3.10.0","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","body-parser":"^1.18.3","express":"^4.16.4","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","raw-body":"^2.3.3","typeorm":"^0.2.15"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.437.0","aws-serverless-express":"^3.3.6","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","raw-body":"^2.3.3","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.15.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.3"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"de88f3a554ff56b9899a2de4e086bf1ecba298fd","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.114","_nodeVersion":"11.14.0","_npmVersion":"6.7.0","dist":{"integrity":"sha512-vQz0SiN1SgfX7Zsqvav7M5yBEVNOUFpxmYXcb+IFVV82HTPIMTEPyRrEfXOyBNMz7AHUBfv0MKY2NDNlldbuDw==","shasum":"c47bbc1e848a03a28294d200a27d260d77a90ef5","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.114.tgz","fileCount":288,"unpackedSize":943784,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcsQDoCRA9TVsSAnZWagAA78IP/iqP80pF60I2JYgwzron\ngjImksACzOGud0W9maI6tvTtjI87Os4xUXBLwZE8wK1s9ttic6sjv8kvARec\n+/v5MThhL174Dd2rKKGiaZJxHmBtaS1wNl2Ke5uOLvIYJzPaQzf2sgz3v1tN\nGyVPWevxyNBfxsZiRte32PPi6lTt1EEuqBGCdPrZnPF6L8SRbdB83qW5Vues\nvX73CdLkS5HGk07+Irw8b8v9CMoPcQMtDKbJYzsAZO+muYVPXu2AEA4AR1o1\nT8fhJRlDiEUhh+n92Oer4L+ML6Tt9aAh3SnhRH3KPGgvdGtoSg1tWkgLpeu5\n3HMmBe0NqoKRujbXyBJ6Ft9m1D5R+Q5sN6yp3s334TJ7+ByF576s1LFjEvFn\npUGFGygLENi/OP1W8cuZKZTArRnXcTXFlLOHlZP/GtdH4N8Gf48VKQonqE3m\nXJ1iYo1dOVRZy61kGQxj5xnzSicdVic11XotDSK6hxf00oNptG243f2cphDI\ngly8aNutVvjNRP5tKoW9k8xDvrQcg06OEfqVjBy0QMSbvZ/kSjuP+fQukuDu\nqZKGkUxigN6dtXDjMy8hcX7QrIht+jXA0E/lFNh/2zfIFH4HfVrBUoz+lTKX\n46L96dtQM0tp4MIfS8g6ngxqzmvrtLpn9OcKkyamXb8bRiauRif+fD9v9jh7\nqXle\r\n=sDMQ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIA5vTinkQIKHuzFAsnT+zN7Cgs/q+fkpFmKpwWwUoqnXAiBO4Z4uvLHvaEhcaTrkWpBeBZbU/a9THhMWn3nu+F38yg=="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.114_1555103975905_0.6703515149022286"},"_hasShrinkwrap":false},"0.1.115":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.115","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","scripts":{"clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.5","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.12","graphql":"14.1.1","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","tsutils":"^3.10.0","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","body-parser":"^1.18.3","express":"^4.16.4","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","raw-body":"^2.3.3","typeorm":"^0.2.15"},"devDependencies":{"@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.437.0","aws-serverless-express":"^3.3.6","body-parser":"^1.18.3","express":"^4.16.4","futil-js":"^1.55.1","koa":"^2.7.0","koa-bodyparser":"^4.2.1","koa-router":"^7.4.0","raw-body":"^2.3.3","serverless-s3-deploy":"^0.8.0","sha256":"^0.2.0","shortid":"^2.2.14","ts-node":"^8.0.3","tslint":"^5.15.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.3"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"e52041707cd47238653d7f31ff65e29b6f9dff88","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.115","_nodeVersion":"11.14.0","_npmVersion":"6.7.0","dist":{"integrity":"sha512-j7WZfxI0sCamRVJ/cCTM9f6piITyGfJ5Go4pf83E/Q73b8WN55LVSxynPM7SUUcDmcwXQgjguB+osn09GkMbMA==","shasum":"abe981b7ca1327a5720433265123cc2608c74abe","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.115.tgz","fileCount":288,"unpackedSize":943783,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcsRdgCRA9TVsSAnZWagAAqhoQAJB4Izqi0N/LXk43/Kzr\nINmZ6kkr8RKyOlnbZWG1wFuSPlGAVixruH9sOcJsj35K7ZF9Ys+gtrli8hkD\nCLDYKQcMmOJWTUtJEHETQihTF1MCebF+ND73lI8RGdGGmqA15rpgwhV7Cg7a\nUb4MWTBTn8FX7r1JTR6Bq3ibXVk0Eld5zUJzXpMah4YQzmQZryr1+wh7nlEe\n2yiS0dZ1B+yyGalX/z17BloZuMiQu8ktOSc/+yjJIISxmoOrrAK+uR4PmtkZ\nHFwDIuWXoRaRbncDKgMLDm6k3VucN/ChLhTlWc5eNc2vYN7reMzONowaoK23\n0hOLUAzxA1kGTFf4j7ZnxFfkrsoTj8aZGV7RAVjc1yhEXcOQ7zSXMH61xQ+5\naI8RHK2VposITfuA7PNV4a4D0GZ2I8++9jMHojVj20dnpw3/6g/jUh0aeOjj\n5lu78VVQJErqeTaVE1b36RLtwlb7C35nKx/BjAZAyS7MUL3GFI9K0K/FXvxk\nSPKa+hYAE72OyhZKf14WNza/JXdxD907hw88WRaYo8BhbDiNX8+YBV1KvAKd\nQOqzKILGj3y3AShWmuM+fkidXOqGU5nYa7h2xyRry5cOYrYHGfKEx5I/jWyn\nkuTEccY727UhEHgzo6IVFteYxxRNV9Ji/wdi5v+a3pU9AIGMb8gz47scE0N3\n6fJk\r\n=37yT\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCTpYAjeJXSOfGaW7VQ3qshOxyNbjhWsbEnJMDkDmcRKwIhAPpw4JF65N0ba512tAT8W5wUqktncjZS/687Cn9j+5ex"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.115_1555109727325_0.7554954672502552"},"_hasShrinkwrap":false},"0.1.116":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.116","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.6","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.12","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"peerDependencies":{"typeorm":"^0.2.15","graphql":"^14.0.0"},"optionalDependencies":{"aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"devDependencies":{"@types/aws-lambda":"^8.10.24","@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","graphql":"14.1.1","ts-node":"^8.0.3","tslint":"^5.15.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.3"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"86d044be5a553d93c19f1a27d864608836beae8c","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.116","_nodeVersion":"11.14.0","_npmVersion":"6.7.0","dist":{"integrity":"sha512-Q3wV2k41Oz9Mom4zt3L2UHNurMo8ynauw2W0EibvvMNbCBgvwr8gES5TBoHAgJ5VEv2iGg659kUt3i0MkjgFBg==","shasum":"03fe22709193632f44ee05ac0c37ae1577cbf644","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.116.tgz","fileCount":288,"unpackedSize":943601,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcsaDoCRA9TVsSAnZWagAAPCIP/jyTFSDOis6qULtqao32\nN9smvd1WIrXfEnSe1t9+bRLwOoY4j5hv005OlnuFbofHFXKBhjFlxZbQysSf\n8OJ+tPb8JuoIHsqR1QN18TaUQJ8UUh/5KHLfKpdkrhQXbHpjinECgzo10wPO\njqAR+yyskcsESZFxZXO8tRqnUlyog62yH04AE45Ld8RnCRsmk9ydVCbINycD\n3tTA4dEL8YCakUMAdGVM1m5nxDP7tbx7pW1BAEZRzAOiHWg7yQ7uDeym7LsW\nHgaokUi0lnMMFckfOwrnCn7niy+4txLDP5tdZ1xVSNIFwTMqevX4IhMnGcx5\nlgau3jg50dVAYZSXiUAFz5IS/C2dUfjh2btG+wfuhb9OSi4mAEtsDbDPXftJ\ng5JWl7lftJT96koBx7Mb5uzlTyvQb6WQa5Ji96CnVkfnqtcbb2lYdaCmVyf7\nRphJd6kGD0Fl4rhOlAHS5+GSBj7wzXxQ7hr0NzNXuqiiUBe9RDnQvh03yq3f\nR4e8Vfk7k1xIsYEcDf/ADtKFfenhIyHsEFV3DpcJJPS9d+Wfv8SAEXBLsPoH\nTAwc1uKOtGp8ybFeT0XQY0AjGcgnWKIuh9oKWt7nlBsU5jJ8o9YCe+CBX3g9\n532AyiSZBTb7dV0wQV5CFTuuCKINLbfkBmMySmyh2ZxNtlQexBQsfCMd3C2Q\ntw1w\r\n=PJZf\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCYEcNzjS2Zxn+eag9S0OljiZ+KR09/sEBaENblXF1YuQIgG70iSHElt9qzvFiglcS1TAK+YdDkiMC0Tbyl32qag0U="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.116_1555144935639_0.8500351146967897"},"_hasShrinkwrap":false},"0.1.117":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.117","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.6","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.12","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"peerDependencies":{"typeorm":"^0.2.15","graphql":"^14.0.0"},"optionalDependencies":{"aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.4.2","@types/aws-lambda":"^8.10.24","@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","graphql":"14.1.1","ts-node":"^8.0.3","tslint":"^5.15.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.3"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"5135c67e6afff1a9ead037b1a28404e7e943b86c","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.117","_nodeVersion":"10.15.3","_npmVersion":"6.9.0","dist":{"integrity":"sha512-0A1xy+Rc6i6+9Fpwh5ZgMiXhK3gmvbgty7hPiNk9XvdpSg289rRm+IEK5ea1Ujqw+jmzcp0Eh7OCADa1hKcbQg==","shasum":"24c63f0624ba83b034b0bed3f962feb3e3dd98df","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.117.tgz","fileCount":288,"unpackedSize":956365,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcsycOCRA9TVsSAnZWagAAu3gP/jdANEkLLscll2kcPNYA\nCPQcCoA/2A/F9ZzKqMHJVvTgSkxwks3bz82BC7h5JWeR3LWpfluSBdciKivD\nBS1P4Sl6VXC2OU9qlx8C3jO5O6oXjcZp4iWo/j+OVUW9svfliYcKSE1CrTDm\nUQB3vGPBNwX2BGUvOGxkp1wC3Yc8cTNf0Nplarxe0v/vbSxlyXlLEJ1pSSVk\nAYciOJ0UuqkqTIBcZHI5g5x6Pmea3XEKa3Jx0i0iX2jofEk2TTbUDYRETYpU\nr78ND0SZ6zOjAkLez4QAnqrI8mMBXp4B0pwFBHFjhmciAMa5nN9iGTlj5ydD\nJ5l+QmRPA4Szb0xa7oHug4nPz0KcRO8lZQ86N9azWAtCwiDuUxi3vo0FVekL\nN8ZfT33W67YiBuhJOT+25fM3J/hQSTPCFMSGIY41mW/1GmCgbqd984Lojluh\nmUqdJUVDIIy9QDmegBbw8n3jX6K/5N+mFw8jyKS+Gswl3oBN8bkvM8aeowTj\ncg10OF5f6H2aGhEBZirCptKAcsqyJ36lGJo1ocgmRASJ5h8FY2KmV1YLF7Eu\nMyDstaPwTZBYlGNQi7NRJ2bxFDBYK24eq2ko4l2e5Kl5fq850xU+oyca/yS4\nj5mlpWB7vOfumRRQ/jdZw87sjBGhqWW1pnMhVaHxvVQ79+l2bQvr67KdRPer\nYwGX\r\n=86zE\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICDb/mTONRr0Tp/oqJt3IjsHj5L1m7h+6fmbjgjyPS1nAiEAmrHhI+KJ4z8zxxYPAVI2oYXIcg6SHZhqm1OgjChmtTE="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.117_1555244813751_0.760195565735426"},"_hasShrinkwrap":false},"0.1.118":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.118","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.6","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.15","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"peerDependencies":{"typeorm":"^0.2.15","graphql":"^14.0.0"},"optionalDependencies":{"aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.4.2","@types/aws-lambda":"^8.10.24","@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","graphql":"14.1.1","ts-node":"^8.0.3","tslint":"^5.15.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.3"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"064d2166b30281d8e6392b94561c8564c95d999f","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.118","_nodeVersion":"10.15.3","_npmVersion":"6.9.0","dist":{"integrity":"sha512-YTwW6EPfDyFdSZP9+EfR+n4RfpVxJJu2Zt/nZc5i9HEPZX7owVxr/TtulojUZ2Bc+FGQBNEZtRj6N+DrB+ZvFA==","shasum":"f9ade4d291adda1f98f8df9a224e6d1f28d10f9e","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.118.tgz","fileCount":288,"unpackedSize":955996,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcs294CRA9TVsSAnZWagAA7YwP/1nUpz98aUhxPsAAuc9G\n+OIafrEdKqj1gkGZYgWUdeXHKp4cLIardZETXYCvegvaT7bEEczrRdY5Mlg2\nXU2eZOxDGtRk98/Vtpek7UbwRVIu48t1jCIbF4081w56caZ1byLY8aLLZ9hQ\n4gVdKYHe2l032jE/DBLTXG3zgzmsqoyeJz9DHs8X08bhyjoDxgXpCP1LkE7C\n97kd9I41izDxVtxkD//0qjFTDhrrvV7FvFDnLev8H9OmEdhlT+DWupund1Su\nn7BQAOq2SVT4xdJRsGIJQgLGqss7NbUXS2/okTA3iBcz+r9EIqELyUz49NCD\n3ol6yBD3wxwCXj9d7wBduwrYdOzHvVY8bE2b/L1B8fbZxmVoVG0boy1CIU8B\nuroIuSAjjryMfV4bwh0qQpJtzQze5zY4+OBX81aNur76h+tygmQrgvhj+Gjq\nY8A9Me5YdisCPLvkr6Ztg0HqhWJjOSWrQ0EUmApJBC241VA6C4mEkYHtCsIY\njhcaqvpNIuijxi6CfLxF8Qtnibfq5Ux0JaFsWDOOzwhkV+JfA6HwVg9KiYaA\nsC9wSj3Gx+IBx8rKLDhpRXPy+z4AmPqmdvyDX52SKwyqfgTj3chdPSi6RZmn\nuCj7i+TNGNhY3Yu1QZczEDqCz6/8HzS4DlhXKkWGVMh2KvVyp//EKyNvCdT8\nF04q\r\n=331v\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICnvQgvopZmzZiZ/Zyv0nqGphu1hnZiFBeQPGjTV6YU7AiBfRNcMdFANJ1LhgSSz0Js2i+JoBeFUp/DotWqeHQ8DVQ=="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.118_1555263350105_0.25393834712430285"},"_hasShrinkwrap":false},"0.1.119":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.119","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.6","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.15","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"peerDependencies":{"typeorm":"^0.2.15","graphql":"^14.0.0"},"optionalDependencies":{"aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.4.2","@types/aws-lambda":"^8.10.24","@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","graphql":"14.1.1","ts-node":"^8.1.0","tslint":"^5.15.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.3"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"25aee61439a7fad5e49ed753089beac706d459b5","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.119","_nodeVersion":"10.15.3","_npmVersion":"6.9.0","dist":{"integrity":"sha512-vI2wEpfqINaVKY3CU2voVgYdoVl164omiv6tKWXob0Y4rMh3/sWCtCS1sMmq4jIPocwq5H7XfmexVBY+9bwQyA==","shasum":"0bfea874e838ba3bd2c0c00003361cd4a6059c3d","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.119.tgz","fileCount":291,"unpackedSize":956860,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJctHivCRA9TVsSAnZWagAAjA4P/iN/Er/q22H+RSwaTsLb\nHu6HzO1O0Z2zMiC0JsBWaaTzkiriKIftfQcKIAG9QXCg6dfTm15Ud8Up9PLU\nN/REabyznyqXQNihtNGfC2eA5hTU07THiVeRENnIZGyYm2XBBrdW6P07Ac7l\npz0sLWxyaE/xbxnWjMIZpnVtjI6/7rbnG7cOLqWDFZaul1bWePhbIu/jso+k\nW4LxzFPjWzuekq5LAXvCI1z4zQlG8/nfHwPKAUXDsgD3MmedereszZwsFiZ7\nXxvd5wgBHiYG5P1eAFtt8Eg2yabBU2qW57uPL05DLqJmVF/GRsW20ukjPikJ\ng7my4vvbBJLLj69Y5wLhZRotMSuDRGThWLU1mzc6O9Fe+SX6yf6p2Nr3DynV\nKH4ifrO3v0bkeHeV1QAfWctqB6J7uOZ/kwpMG9FrVN2ycJUiIb+eh93saWst\nbpLe+kX8LqJv78F8/kbDnE9Y/OGNqhEJo1uTwIALTFe0/lOO3foWatlOtPdv\nOuUunkS1ZLqL4yuAhu+5NSOnY7ZQp42LKOOcphKK0wMaijVBad3kosFpxb1s\n0Wfj7nOAUV4zK64ZOSxoRWymSI/WdWgmEKHSOzoKwQFfb6SGHUhNO1WZaUyd\nSvpKjHcIo+DA8eUd5u+STS2nnExIHTXNWK+xa93KgczwmY43adREHLIqlBfA\nxB+g\r\n=AFKd\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCZ1dRBjkjMkH3uT3D//z574MoK3oeqrR3KDVLKCrLsgwIgeVBSaqFexoZmTJqDFx2mh8uAn+RO11CfuRWhAn3fKu0="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.119_1555331246879_0.9850941322784974"},"_hasShrinkwrap":false},"0.1.120":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.120","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.6","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.15","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"peerDependencies":{"typeorm":"^0.2.15","graphql":"^14.0.0"},"optionalDependencies":{"aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.4.2","@types/aws-lambda":"^8.10.24","@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","graphql":"14.1.1","ts-node":"^8.1.0","tslint":"^5.15.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.3"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"3055dea04fa80e0890cb73edadab63cc2cda3810","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.120","_nodeVersion":"10.15.3","_npmVersion":"6.9.0","dist":{"integrity":"sha512-ihGqmIU+sEiy7+ucsnLzxIoeLVerdddgwj3pttD70whF1los87DalJXnzhep5VfXKerQ9M7ytQ7RveGU/PJZBw==","shasum":"932c9e2b293e0d01a68be5236f3eeaa8670b5ea2","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.120.tgz","fileCount":291,"unpackedSize":958606,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJctb7fCRA9TVsSAnZWagAAom8P+wUB0VpsY+vXlR9ffGro\nM2xbGvJMuL1Zb1byLdUq5vw2GP1Gsvw5ZyD1/gqr/J4/BZUtCIJAIq9NjG0S\nGrQG/cAq8gGj7wSlYHUyqreIgIW2RPndlEfe7JLraH8r4i4/ezg9v2E0jeUn\nVN50uy9srzZ9qDUTiN9viiRWx7/367jpt9BZO2nj/1qUpIcA/x6x4g7c04FU\n/b3LdnNM2QvTKFZjhR55e2Kx/Y3nV12rIsEY5FrIcY0OwFQWcd627uDSinC2\nYCZoQALdpTpT4XvgIC+ypTeWNJrvg1ZL/8lRJoOUOJ+It0o9hHIpc4id92ka\nzpD44Qab1HxIPIVh/fq44xFTBDAWElRIko+MBqMgyKuXfmuOq+4HJAF/ktEY\nz8ub8EKNvgQuw07ypyUKpwp7oHTYjaC3xxyshrkd1j5lVw62GTOHdvx+vccR\ni1P4YCCxUZrgViA488DvWAOX5htnRPVKvUU6q4iMTJqSzBkSj8m8ZJLWD/b6\nX/VTKNgPuoXwECJOcSh+OPRlVoCbCkXyu9fLvZFeDuOdee9+zEakE0iJNVtI\nQ98jX0B6DCK7fdDvqVOiV0DOW4xUkWj/LKEstTBYNn7IJhOZAHfkqlbWv8Oo\n0LYFAjAbHCtQ5L/dBTIBPSSCkTqzq1vN1Gtp8U1XrODdkO+SRajMCyxxjT2L\n722P\r\n=8jNa\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIASf6Bzzjbrsqeu1Q+qO2VQYgL8+nK3R/rWPhPdi1PNiAiEAhoqylEiPKChlyTtxgqrns8oiBncn8tnebQAJ20/hImE="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.120_1555414750256_0.3278119556259045"},"_hasShrinkwrap":false},"0.1.121":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.121","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.6","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.15","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"peerDependencies":{"typeorm":"^0.2.15","graphql":"^14.0.0"},"optionalDependencies":{"aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.4.2","@types/aws-lambda":"^8.10.24","@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","graphql":"14.1.1","ts-node":"^8.1.0","tslint":"^5.15.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.3"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"732af1fb235552f9ea3483e0c021ba21b169cc65","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.121","_nodeVersion":"10.15.3","_npmVersion":"6.9.0","dist":{"integrity":"sha512-U9qDzpZvtKZFe0S4wMxYpM1dBORUm7q/e6fzhEvGqWN0IZ49HtJorS+ECS23cm0IKuZVEjBwjjQlVsY+LBRTXQ==","shasum":"8bcd318019f78619de6b5bca904afedf02dd8625","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.121.tgz","fileCount":291,"unpackedSize":958607,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcteHDCRA9TVsSAnZWagAAdSoQAJnIxN8PljDr18Tq8EC6\nEZT7Xcgft0FA8BA0e8wLgpWsyO8wAO0gljyqd2Sl+FgdqClgZtC0zMI2SqEN\n6Ts0eE9iAf9y7tsPRyMWi/8WxtlSb1wNraiQyZh5ISrD4pFOpTaz4degZA+l\nplGHKqGRQW56NH6UsOsRcQJ8Vo32iVC+9n20qvZIIAU8FZa/d47Grj8B8dqi\nV6l8vFY9Tajz48qzScDmSBmhha9ri6sx8C3k4LqYvDo0TSm7XMgcnzFsgoG6\n6LH7nUnwwMzsQduBcIGVDP1OkMdS6mlONBUs+Fp/oh9ScvFai/QpfKfMKdwT\nXsJITXdf9AUKi/lMlJ2eBpVE9A+FRObJjwhfwK1wvLO4+//fqWeB30TStjkS\nxfi6/00Xgc5KKI2L02yKjiX8aI92U27zvNp23tYU3XMRW60XYneiQ+v+QNe8\nOwPJW5WIhuWzkr5WatvZwcW603JLIvpPhlIC+GDgXKanIfNM3xKN0afTllr1\npRktK9K7VVpu+9taqmQ872J0ymA4Efvob/gbwcIUs6JTY9kUxsHZXkrkOaTl\n0cMZFjfUHskkusjb8orf/rvOnMoNV21r1rw6lwI/+q+oaPPWFQ8LgxOmJVND\n6qOq7cwro/CTfQqRkpvveGu91+4t8m/DUCdnWVDFLRpof1j9IrfoKMmj0CrE\nlJLk\r\n=6WCZ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEl+m/HQjck3YTXiJbkj/y9W/1Hw8IyLstJFONwrFaFAAiA83ukrXGAjURA2QkwrQMw0TV0axvXZA+WzbsHyrGfV0A=="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.121_1555423683102_0.8174476529198009"},"_hasShrinkwrap":false},"0.1.122":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.122","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.6","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.15","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"peerDependencies":{"typeorm":"^0.2.15","graphql":"^14.0.0"},"optionalDependencies":{"aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.5.0","@types/aws-lambda":"^8.10.24","@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","graphql":"14.1.1","ts-node":"^8.1.0","tslint":"^5.16.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.3"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"d5ea1c6648ec0de2cae64b13a7db4c6aa2267449","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.122","_nodeVersion":"10.15.3","_npmVersion":"6.9.0","dist":{"integrity":"sha512-d3ZMBYUymNymkDziwnFY3FgD6oRcldlDht4WG+jCI1Z5XZIUOWTaBp4Kv55reQ8Exu2qjC0pwDM6YysF/ttj4Q==","shasum":"17e9f895dd90557e705119e22500ef17cd6d7e5d","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.122.tgz","fileCount":291,"unpackedSize":960258,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJctvbTCRA9TVsSAnZWagAAfn4P/RURjDjgKLqOXlpTLz8r\n1ZOjirr25Fkaue7We0CGZoJF3YZ+s/h3k8lR7yz/eB3APfmRNw5HTLxkdrj9\nI4wLs8rK5cHNQ9wkfexZMq7Boow/5kge1szZVrNb105pxHyDN8dI7H2yHkx3\nMKYrSvg41aaM7VYrSOnmtQTENjYJx/QI7PkpfeC0VYEXhCOgZFkaupMfKSes\nT8OfBRXug0yQuSZQ0WiwWmmXkjQ+FSwRWsD/alIrszvf0yyMUye48nnC1zLD\np1TOrCGvQ+N1U9VGwcS+Z8ELchTaeGWROmD91ndh2RCIcUzxBgD63Unco7Uv\njm+owARk25DKORHU/DaS6+2Sv7uZn3AjXT48ykgnS5fpJmXk4pwNnuFtTsHu\nCbEQRecUjWnck6m2VZPbWsKHJ7XeRV6r65ZoB81TSIf7W7w4rdACiQs1yLdC\n3VbJjPj/8buq4/MuyvxZcyoJSDv57ZRgT9t4vsJwkMK4psWaG6TuYWGnX/2E\n3bn6LgKolMedEPTSaz+maqK6dtqCxhcrgRGl6x7viGzVSvOSwY7jLUMq6mPw\n8pNkRE8PkvYedYy9jTKZzaS4Ve1D9MCxJTLfcB2baKJKOLARmSOXWwc0bQDQ\ngf/8jVLTgCAoupXwFxCkIvZh7zHU+1h8Y7BQrrrNOBgLi/1bgEHbDO3dT3r1\ndWVo\r\n=10GX\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDPZB1x4V7AJg1qaT4Vnk+9pXSFh3zzAQ9inQokG4cT+AiEAs9+FidiEGCVMDGpxE072OJ7o+y1JEwd0G9OPqwM7BhY="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.122_1555494610243_0.7153302176405203"},"_hasShrinkwrap":false},"0.1.123":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.123","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.6","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.17","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"peerDependencies":{"typeorm":"^0.2.15","graphql":"^14.0.0"},"optionalDependencies":{"aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.5.0","@types/aws-lambda":"^8.10.24","@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","graphql":"14.1.1","ts-node":"^8.1.0","tslint":"^5.16.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.3"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"be46ba6de66dcfd3a23cc36c878bde1f5f0a55fb","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.123","_nodeVersion":"10.15.3","_npmVersion":"6.9.0","dist":{"integrity":"sha512-L87kRURY2C29JJB/fI81vHhY3fHQWeDV2Jv0bbjHyBCFbVTyPfmoxK25i+Eo2r61nMC497mRUmGtfuaBJlIQew==","shasum":"4801348282c79b83cdcaa2e7a94ac0561a650d68","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.123.tgz","fileCount":291,"unpackedSize":961344,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJctwqXCRA9TVsSAnZWagAAbrkP+QGrJ8lLZz4fcM/te0ID\nb++BfbLR9HDggeVVx1PorQF9p7cg9PQo8NE1s+MYP6mQGNgI5cJTOKiQphy3\nHqCW37za7Lv1/B6dDQQ0McSSW9fLVMkt94R18WHdgIKJWO/l0+Yp+HQ+KIXJ\nOeMI75c4cGKxB3nGCdk/5YyKPg8vFVS0A/AltZD7BdwhujTN5hPMJN0Z9Soj\nzg1egUn7chm8bENM3MYLIq8BMBmdRK92iY4HDusZzHkHG/mdnBIJbmfmsZkz\n72Cff8Iquwx5GnMUmp/RiFCf6ev1tOHcg996wmOk19uek6SfQV1PJIZyQazF\nXwH0E39ymt9EzIMMbTDocon09zSysZXm9cQ4/qW9N9quT6wUf2qK1TWd+Rvh\ncNfiTpGZsjB4e+hpVwnW7JzU5zIhCSIPpGNjvi/gKuyWRYMvn+IUmsx+Woyf\n6gYU0F/j8UoBagvikigAUOpwWvv4cehVDwJ0tLmQIVCGeFNoM2+mnE3dhBlc\n81AVJItFPVgFg5Gsb/A4O28/fyDGpoyMl7Ifu+EZHthBWFPO343aLAkT62bs\ngaTlcCzGF7lzjEPTciNfpxFmyrtUSWspRoH4jULQfbkUGzWMWGux2Yun/sYm\ngCQNuLLnsUAVw38nMH/7ovpVQRsxcExBFxxH3oAViHLoBV3z8G5lJoBOx7T8\nApYU\r\n=+G+j\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCE9t88MI6QnDdkk5h/Q5KTLC3Q8LHpuftTZvfA1WZ8/AIhAMJ9LzxiibfUfauLz/jwkgJU9BtITkHxezu31dWu7FKU"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.123_1555499669997_0.7820308145535744"},"_hasShrinkwrap":false},"0.1.124":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.124","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.6","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.18","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0","aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"peerDependencies":{"typeorm":"^0.2.15","graphql":"^14.0.0"},"optionalDependencies":{"aws-sdk":"^2.420.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.5.0","@types/aws-lambda":"^8.10.24","@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","graphql":"14.1.1","ts-node":"^8.1.0","tslint":"^5.16.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.3"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"ce0c9d580e37214ead0cf2702e512f2c9db0026a","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.124","_nodeVersion":"10.15.3","_npmVersion":"6.9.0","dist":{"integrity":"sha512-TCcd32asnT5lNkQFt7W9L2pisHgNi1PpB+iSdkkQ3N2wPVrizfpgVLGzGgX2Pf6PPpIu7DtPRIRoQXZrNxBvWQ==","shasum":"16f54999777b1b10000a49d0deacb054d8ddc9cd","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.124.tgz","fileCount":294,"unpackedSize":969681,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJct0M+CRA9TVsSAnZWagAAgJ4QAIuNydk0KJmPxOYendH2\nufcB+NVBBRTfUo1ovWtHi+z/2xIl4lPelTABaKBmuNqQ0nUZlO3VTLF4A/NL\nMBFZfGVTeVw02M8L+N+MFIcJIFUe+TKOeK50zr3j53FP+JnYgiigicp5Hz7I\ntGUutd0jR9tB8Vq7RwIXUJb8COm+SCos/hd37T4Ya5ovM5WQnaKutky7JRV6\nJCXVvXq37a7EOQYPwVOJQzFqmqfR5H7zc1olEhUa6HQADtDuwSk7SLM4qXv/\n/M945ZKqcABxH55uAnq10m64LRyd1ttt3B31SDE9mNQp5aWAV0GadSuQ9nVo\nakP3oDeQNN/k5m3hV/Y0rlHPJTepgC4jQkhBkfYXCSofO0qj13adPDcIYBmr\nNzDlIaQEXxNgqVJ7yyDtDxbQ3w7NMFvQu9ZF2S+rpOXjACEM2YCW8jdTSpcJ\nnisrbrx3q9fn8xqX/YmGfsrKsPxY/9GAxxHpkFYYseqEOLG2ZJZrXn2HUlLp\nZDTWZcOlOQ6EFV/R798bauvTiw15f9FjowgLvgHVZj6kZI3HYN9POlEK2a1P\nyoPc20fPXTdcmv5ka3Ic4yPmOr1SH2/w5DmqRziaSIpuyvhY1T9RdT+Kei0l\nEIYtcR6zcLjusciAQ6OfV7DtjUEBBuyzbSplO4LyhJbnwc/3UXODJNZErtnF\niqtp\r\n=nwCJ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDDc0uAzcqnhH0seJIF8E6nzpoarKI6c6h2Kdz7UhZ6TwIgL1roV21jCxUC+Oz4Kolt8MnCL1alNlxtfbdvkx6SLP4="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.124_1555514173232_0.8002956777023922"},"_hasShrinkwrap":false},"0.1.125":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.125","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.6","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.18","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0","aws-sdk":"^2.438.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"peerDependencies":{"typeorm":"^0.2.15","graphql":"^14.0.0"},"optionalDependencies":{"aws-sdk":"^2.438.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.5.0","@types/aws-lambda":"^8.10.24","@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","graphql":"14.1.1","ts-node":"^8.1.0","tslint":"^5.16.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.3"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"a14fb563fd14724f0d6dfedca9299a5f57e0191e","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.125","_nodeVersion":"10.15.3","_npmVersion":"6.9.0","dist":{"integrity":"sha512-D4c/N0DL85Yy6MYOk3ePKHyAcRqUlzs7Y16nuyJ9JnowylaWAq33TOPkGRDDEcxQUesiQyAfMpbruU0jUF13AQ==","shasum":"893fad60a8e51d96349672612661eac149e4a87f","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.125.tgz","fileCount":303,"unpackedSize":1000235,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcuIfcCRA9TVsSAnZWagAAIpgP/04q4EpioHZbpx6Y9Dtl\nGgFmXzwfoZ/vjlnvxRGJ5ctcV/k91CmR7Euo5X28IWdG3Va+qd59K2rj5UfH\n3Zeg3YcGbZkZ5LwsTxJ9auFars74/LDZvHpgu6NGQkjuZi072ioKTlswx9no\n01PfrETXI8KLc/TpmnALh440PAYnZmJ0LuVU73YLmxwVWj96P1PYyVLqbr+j\nmDKcFzCL3OfUhGCmHIw0X8GuPWo88/2x7qUsBfovC3R4vvgnVhlf6pNtb5T2\nSWa3uzDRyO2hUjp3hSzOi6riLJWh4rwT/p0P0HfHkuRiLIvNKFVJKu+U6EW7\nw7TnpqLPiQ34mo/stb/6kgPhTq//31Vc7dS+/gJFkekuMdCsCkKoIUCVK6ci\nJyvKJppM/LVyessT5dpPaeuqPCkQD98PV14wEMIR3T32KehSAh7djvIj1YOW\nmouQNzusaK+Ce+MCsUIkV5BXGfs7tyqOHSfRiYOMpRLI8Dcr4pacUuzKwjfX\n2qk/hxffvJcDyCLy6ur5p8Fmn70Nl8oMqfxRfS0LcDOoX8Zx3zBlraIZmccC\nd+TDFbyEWgZJ5BLc8Z/72qQdDyxSFizdwy3TWVZHKIGfL/lGUIKL9am+9RVW\nl/hOQeE+dpNr9N0ZhvtbPuEt5NeX3CM/4lAC1Jrare6YhbOHGd4wY6BBzvhg\n9Vu2\r\n=xlb5\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC4KPEiAUF6+n6+2RX1p0y4MRT3cG5fqPfG3QI2RBBZUQIhAImwmIvhPOOKAiJc16AD5T4XaygbbssoCYyNNasstVCQ"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.125_1555597275837_0.14033954713670416"},"_hasShrinkwrap":false},"0.1.126":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.126","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.6","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.18","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0","aws-sdk":"^2.438.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"peerDependencies":{"typeorm":"^0.2.15","graphql":"^14.0.0"},"optionalDependencies":{"aws-sdk":"^2.438.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.5.0","@types/aws-lambda":"^8.10.24","@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","graphql":"14.1.1","ts-node":"^8.1.0","tslint":"^5.16.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.3"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"0aff7beb0198a12cc35ac68597c8936834f92e91","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.126","_nodeVersion":"10.15.3","_npmVersion":"6.9.0","dist":{"integrity":"sha512-FqlEz9P33Wdtj8NErorJ8URlqcn4dmcjx6T2B3n82pGbNU8bAqAWTaPc31uKGGDpqgIP+OqcdHuxzwFHVOQltw==","shasum":"0d9db0350cc45b14756233f8f8da9a3e3a6d58ed","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.126.tgz","fileCount":303,"unpackedSize":1005895,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcuQHcCRA9TVsSAnZWagAAOTsQAIo53SRIf3TA8Bua7Thq\nfpxZalP0MLvmervlvxWKgDGY7bEBfEJQDuVzk7W+t3DvLxGybXNw31lnH0D4\nWsh0i87Fu/qMUGbJrlw6Aj8c4r7eSGyTntnOiSASIGAnT6sz5zFacble1Ry7\n+l973QdCh1aihBt1iXYnPzF74DOotdWWqzfmcpfLY+M3gKcrhdnjjsAZVYyn\ni2NXvrpLd6sLgVKpW2mT5ytjIm5VcruyUWoUg4hcwsniFKYsVhvrdK2+QG1o\nNpHvRrAVBkP+lw1EqgvxUqB4ybo4NNuDeCH8iT40+14alTP0tLSVO4eylBW2\nptOBRb8543+cjR01/NkuNG/q01szY4bLHT0mpd+x4CsPuax55uXRnoAPG8l7\nScMVQtjIPlkC2N2lhKBCXnweYezmpv1kbhtlTNiZX9Jm7w4aSEbbUfm7vHDP\nVEjUR/WYMB73TEzrx0fIDJ49aVRvoowh+UUOGLu5VtBLI4HJSu3oxQMFJNrz\neTja/IXH9fyTS5hj+SIbwghf1Ly0S+4LNZQ6sE/bNC6f6VJaMDz+bAjW65UF\nZQikVO+sQlFqvsANOv1LETp68EOecZiGSkJbPmZljFNAxUaum7Lx9u78zqn9\npBzI5eVqm5fwXMcbDKNgqQ7G0knyQ0OxyOOinq9UdQxlDJERUUqvNYi1ENCj\nYv1k\r\n=/+4k\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCZUBm0c1uYD3LWErLbq7VNRXiNszS2Ww7q87gg5zS4lwIhAIa1Kfq37+rf/qALSwiBP4EOzpBTc5I/61F1WjIhE+ON"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.126_1555628507170_0.348148545291193"},"_hasShrinkwrap":false},"0.1.127":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.127","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.6","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.18","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0","aws-sdk":"^2.438.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"peerDependencies":{"typeorm":"^0.2.15","graphql":"^14.0.0"},"optionalDependencies":{"aws-sdk":"^2.438.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.5.0","@types/aws-lambda":"^8.10.24","@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","graphql":"14.1.1","ts-node":"^8.1.0","tslint":"^5.16.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.3"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"cc5a59b5fc7694ca0d682bebe7cb4f2c80a86cbb","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.127","_nodeVersion":"10.15.3","_npmVersion":"6.9.0","dist":{"integrity":"sha512-qzEKGHg5ZG3Sx9ZKQlzoF2dDSN10pF0joPRA4TVxY2u91HTV7mAG+VTS0wl6oHgh7JxrPkp0l4ty38cm59eM1g==","shasum":"1ec4e9c3cf97f42429c6518459ebcd82c7d4970b","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.127.tgz","fileCount":303,"unpackedSize":1005915,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcuSBRCRA9TVsSAnZWagAAqOIP/2QEElk3OFImxOyqCPKm\n38/wNFgFBgdGTSlJx3sgeX0zS7lToHQkNZMhNul3oAtB5XBKn8byQ73uINYq\nocH4gEH4MtrIUGDg/2spZXgqpgMfb1XoxlVK33yFRrJiJSWPC6a2dkbmqzKF\nlbVUB9+J7imYMAwoEvR7YOsnTo9IPAe4RLQpH/01Q02gl5lqx4Fag1Kk4VTp\nCl4jVFs8pO92F8HHIlXijdI/Ea4PSV+NUi3wShygoGqjW6BB5s5V1+MiCyO8\nFkm5qAYUH90Jr8szjONKSXgirKaQYjjnxivZLgw9e0QlykSiZ4gFx/DcZP96\nh/4T7n2AnqwsizZyUL/wJUHlAXHTcDg6aeqGMxqNuspAkeGV3VYymqnZ/50F\nDbLDlXCqZ4itqZ9ZLQwBZ13aYza7OkRQdOnok5jLk5r+1zxOv5VP3M1ceh/c\nHQ7qeaLgO4x6AwtHVG+Y6HD0F9SW/uEZKM6lZy0NvpgWEKSCVFRkhjyFbtjB\nNna4U6JIqNL1EeV9BuzeBggm/a6IMr4VUgHEXmBWNiqosBnK+xaOfl15i3ta\nx4EZaJ29Pck/452dIMi8iXi5aNRlalR/SweFlZyFHLa9jBvGzm29hXshw4Nc\nV0hD4cSmTTAlSzh3CDa0JdHKvdjSNtPYNkvgs4udmCnuZ9cmhkkhyV4y58yW\nk22V\r\n=RUIn\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBSX6Tc03jvpjpkfV0gZu0BhOt9ESI/C9SXaop5y/Uw+AiEA8b59K98vNsoCr1B8jr+9zNo84sLdnwfSYbHjBv6kMIs="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.127_1555636304221_0.9236421513651072"},"_hasShrinkwrap":false},"0.1.128":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.128","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.6","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.18","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0","aws-sdk":"^2.438.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"peerDependencies":{"typeorm":"^0.2.15","graphql":"^14.0.0"},"optionalDependencies":{"aws-sdk":"^2.438.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.5.0","@types/aws-lambda":"^8.10.24","@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","graphql":"14.1.1","ts-node":"^8.1.0","tslint":"^5.16.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.3"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"ab278841ad616ab5e948303ef49000d681c52b42","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.128","_nodeVersion":"10.15.3","_npmVersion":"6.9.0","dist":{"integrity":"sha512-A8q7gu+i21ZeFrqLLPJB9/NufHaYNW7n0lK6YmBDK/V3e71ac7Rd/5VEgHqxyjZAXjgCdkXCH//hOBl+EQAyYA==","shasum":"19a5cbcd73b8e3c71bfec09cb85fa13fb05bc060","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.128.tgz","fileCount":303,"unpackedSize":1005921,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcuSV5CRA9TVsSAnZWagAAfqMQAJrUYX7+Q9MicJVLUG3f\n/xGcWjPy+kEL78Pk+r48CZ0K/brJH3PiBulneM0dAl72fTzbsUmPm0Yuv/x5\n7wjzr+nrhZWNBMvK5qkxpt7ngcou25hZ6oH2Gm10SBfAlQGk+Fmuxe2nbQCR\nTd1dBEmS83OaZnmHH8EvBIodCTd1jXrbYQFRFIkHYES+L/4Ybzf21EkOGd5U\nK1kMEoFGNri+riBIJWvWNq21XNHzBrwiTfLMECIA3mtqu2Br1d4LuSHXMX78\nGa3Dt6rwLkzqugtCzl0a5PqjA9dgQuzcwCe2/eJ8AL9SkGmCvKUlt2kFK/Uh\nEhqcm3yss15WhYhnpFnmw51Ql2pq45/m7HzRYt38hZC7efcb/Uo6C+lY4ONB\nx7myNXP0rHUAw29+Q9VREKrXBpqHO9GSfg9g1LWvGd94I8pqUld1e99nq1Gw\nceriqxD2NXOMBvag+e0RbGhJZebDZX2wN4OAbP70l/yHybAYg0zk2QEiB0ts\nk54ywbiIUU5/WrY6LhdIYSa4fYJoiaaPwpMweMEFprXQVDlVqJ4Y8C0eIRpT\n4g6zpcLUf6V/J0n39Kt2wl9STSfwlre83thqaKEBSKffAWymk7y95fiT66cJ\nQJNcYnIHqcMdfVWxLsypNln5fAdQuLMtmIP6Xwh7QJXA9iueDoUiGvrXqSbp\n/iBo\r\n=KfZi\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC0STb7YSvBm3JYyTe87FnU9KDwoz4gMJ6A3Mpqn5VAJgIgK6x72dbZMy6qeCF1RK+vFgkB/gc31fwbXZAkFK/MdZA="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.128_1555637624773_0.36334942613033605"},"_hasShrinkwrap":false},"0.1.129":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.129","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.6","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.18","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.2.4","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0","aws-sdk":"^2.438.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"peerDependencies":{"typeorm":"^0.2.15","graphql":"^14.0.0"},"optionalDependencies":{"aws-sdk":"^2.438.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.5.0","@types/aws-lambda":"^8.10.24","@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-bodyparser":"^5.0.1","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.4","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","graphql":"14.1.1","ts-node":"^8.1.0","tslint":"^5.16.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.3"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"05f1942591693eea282e37671c573dc25bcdd749","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.129","_nodeVersion":"10.15.3","_npmVersion":"6.9.0","dist":{"integrity":"sha512-9hXFx6J6Ux50WRSTiDSzBQ3HFtyAl6GTo0IbdkYCuNocQpjJD1dBxXz8/rcH0XNRw+x5CwChEgZeSYq8cQa3wA==","shasum":"4044788d18b42b9e586f365154ca456ede7ac784","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.129.tgz","fileCount":303,"unpackedSize":1006062,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcuTNtCRA9TVsSAnZWagAA2TkP/0NcX7zE5aANIsxdCZnW\nHJn4ocOqHOF0GjnCW+DL/fdLMGslLL3g2sjHBGsBjCFD7R7JbaRnVC0tHqUq\nAD0+VC9ijGliYh31HOKVRUWC2GFDhO5EiQXMKEwC3sLV3Q+7+tzMgwi+CLNe\nkTwwRGHBRQHsntvUIsp99pUHen3edVBbxvKsmD1w5znHq31Dq46xcNCa6xxQ\n1zb6PiU8LKfa98WFCd1/yb4W3/4VB106usu0aMWMKNH1Gyv06C617aNtkbE1\nd9/Wg6AW/QlrfbnWgJSTp87DoZ1lvg57lkquJEq58fk1LPe3q9YAX+0XLDxH\nuupyQ5CEwPGErdmmmgMOI0M9JvWR4Xr5krfYtJFeeXpPVIzathVrYUms2F9T\njmjqMohPq3d/G11MyWEEOjLdXr0kC4QhBwjBXoT1oWSL3fbHFiJ8gmqyIRPb\nU4CfibT2wbVvKh2OGd3m6iBWidcNnM2xI3Gu3KO3G0OqSqmefn8gUjRJrJzf\nB8QJGIeWWwe9WrMsgLPFy3FM7+H8i9ESuaae/1AMwXrivmNg4pohwto6M3tU\nZuCEI1eZE5rcQoaXQnmcVly6Tk6PEwG0Qi3Jp47q0k00+cN+xxQK2Sgs7NwD\ngLN+K+pKYzTf1Rz2Q3TIJ44oRaLe2X9c/Fn2UtKGUtTZLAtXVIg3ro4ZByOQ\njd40\r\n=VC7j\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCztCMaFbTVQ8WVlt3nNObaCF8VZ64jY14J+JZ3oVoQcAIgLxQ40Ot6DDKFsoMEYWryuUbiGjbhBc4RSKo1TSwbcAk="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.129_1555641196988_0.9732625838182707"},"_hasShrinkwrap":false},"0.1.130":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.130","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.6","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.22","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.3.0","jsonwebtoken":"^8.5.1","lodash":"^4.17.11","ms":"^2.1.1","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"typeorm":"^0.2.16","graphql":"^14.0.0"},"clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"serverDependencies":{"aws-sdk":"^2.438.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.6.0","@types/aws-lambda":"^8.10.24","@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-router":"^7.0.40","@types/lodash":"^4.14.123","@types/ms":"^0.7.30","@types/node":"^10.14.6","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.446.0","aws-serverless-express":"^3.3.6","body-parser":"^1.19.0","express":"^4.16.4","graphql":"14.2.1","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.4.0","ts-node":"^8.1.0","tslint":"^5.16.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.16","typescript":"^3.4.5"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"c702ccb570d34f8c49e2650595af363970620df5","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.130","_nodeVersion":"10.15.3","_npmVersion":"6.9.0","dist":{"integrity":"sha512-mse0UVbh/flAt7mxvaIqOMqRyzEnJmPmkvbPz0UcqSi+B7ol3L5DWw9t3SBQgw3d3fDl4oLSWwfpAl55/pvh2A==","shasum":"2ee0efdaac6b13d566ffdf2c05ef0d014fdbed14","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.130.tgz","fileCount":303,"unpackedSize":1006178,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcyYDcCRA9TVsSAnZWagAAjFwP/i3zLB0gjncOs779lCJd\no5FcB9pSpPbGExR2Gzj0qSEkeXU+yCWJJ4HioYCB5UOq/0VjKClAPa0zNh5J\nwVvIbIYDtz7kmaj17WDTSTHww2FRJhPmEPGL9S7NjSMJhU07J3HW4QD2Uanc\nLBHKLYzALhv7cIR/TDTNz1B2oAzgRUZySBS3Sp71BAD5TqbRflG1vLu2HfW6\nP7Beij8gUlcpT7NlzC99PBsrh1GialcM5qRPl0QyeHIq2zpyhF6RHMWhRYBx\nGel8HzWBz7RUpBGqJ2lRti4RH3JEN8HKpwJgnaXoQah5oLdk9SYjO5yeHdqH\nDEVk+mZO0QQohVOhqG4ie0VBvUOBjP56DUWipPWAtXPRKKKlNsgBI/9bSycJ\nsfoEwTUaQMKlCLXi4rKjiXsIlGtK50sryQGaAE62fnIWgjJZXD3tvzLxQ/L7\nyWdygBuTPfC2A93r1YSrTMlJj32LxQGKCD1jaOenpl6q7OC3iuODujBXGjrc\nFVSS7m5DPmDiYEmMXSNP6pMTz3YvDjLIc3ITqcoarpQI+EIg6hlhDukDZOCU\n8D8njwnhDMK9E6MQ/QogYXKmx73KF5yuX/kMoZhBAteInkijPvvG9fPq5ykF\nwaEAsz/+THvB7ljme5duWu24vXgkGuT+jyKRBg7QpeL3vpb3sCCFgfrmmv8O\n1RWX\r\n=MlPc\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAHEIat+SZ47vT06be5YCZsj2v1567/AP4iw1VHKcAUpAiAUwI4eh7ELd/0BQTXkCFAtlsZ16QXXE/SSVJbE/fjokw=="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.130_1556709596137_0.6471869388142131"},"_hasShrinkwrap":false},"0.1.131":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.131","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.6","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.23","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.3.0","jsonwebtoken":"^8.5.1","ms":"^2.1.1","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"typeorm":"^0.2.16","graphql":"^14.0.0"},"clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"serverDependencies":{"aws-sdk":"^2.438.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.6.0","@types/aws-lambda":"^8.10.24","@types/aws-serverless-express":"^3.3.0","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-router":"^7.0.40","@types/ms":"^0.7.30","@types/node":"^10.14.6","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.448.0","aws-serverless-express":"^3.3.6","body-parser":"^1.19.0","express":"^4.16.4","graphql":"14.2.1","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.4.0","ts-node":"^8.1.0","tslint":"^5.16.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.17","typescript":"^3.4.5"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"4a4df259046e82f2373420575fa6293b534d50f0","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.131","_nodeVersion":"10.15.3","_npmVersion":"6.9.0","dist":{"integrity":"sha512-vEqKNhD5uO3hIr3Bp26WrNrkgIq1ePsG/+Td8uUupKnG+TdyKbWd1oX/QuGNmlsep67UIA/FVBYmMdKWciXfJQ==","shasum":"6c1636f0e6b800f0908ab9b5a6c9156cfe5321a5","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.131.tgz","fileCount":303,"unpackedSize":1006508,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcy1H5CRA9TVsSAnZWagAAS0oP/0NKrtLAyVDAcwmfLM7p\ndY+6PR1yKh18ST8gHWyT501ymJPFFQX42waREOjRL0b+DSwJFswaFsbPKe+H\nT6grb362g6iTh/PgFIxuZFB1KTeFVKDGDY/mLjFnBIznb/GaxTA17xw4LvMO\nfw7pfVQgUi0P0JKCEx6YCwD/xxzeBRTKQVLFna//de7A+o8FSseBFEQUmgMz\n/ltrQemkvua3u8+cYb4hEDYELxwnaUdbeOIAWxQT11IY/ueiDXLk4DZIc3oS\n4GEMKHZtIijjXOIoOU3fCBpZJ/lXGdh60nVwIg0dNjl+d1CA+T2XG14XZLCT\n0ZTbwg7jeoJy2rxLIgvjPUWfuG6RZw0SeZ9Xw3IxdTrsU4qyedXrjHTf6JZx\nfw7c76K7GiKs7PENht89S88XdTK4CLNYXZDNTPP7sUO6zh8ZnfN9p4CvUcqN\nKIFXOgsglduRF8B/QrE/hCODPZIEt4/Jsy5a+p7kBSDeIN+jX0WWNZLxgfAP\nGYcZzk80GiXp/Y9Y5vWU6mzhVSquu8SC2u1+qvgd+YnoKlMlg/T0Ww9hiBrw\n79o18DfjIklJ62hpEPyer4A/vsVUGu1AZa10x5bx6/BMmDQ9RIIfuEPxWyWH\nNc2dOqFeFmTBJ+e4dLFKg63KMVwmejYDLZYEt1iVHWSq/5r8nWm+SZxD1Qv0\n+ynL\r\n=MjG9\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDulCl8GoHFwaZ2QbFqHQ0SdaLvssKJKVkHXooT4NhEPgIhANM6j2sK9v12EpsTrmvUQzrtMdnNCB+fuhPRFLHFO58Z"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.131_1556828664716_0.41429166318300514"},"_hasShrinkwrap":false},"0.1.132":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.132","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","dependencies":{"@apollographql/graphql-playground-html":"^1.6.6","@creditkarma/thrift-server-core":"^0.13.6","apollo-server-core":"^2.4.8","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.26","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.3.0","jsonwebtoken":"^8.5.1","ms":"^2.1.1","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"typeorm":"^0.2.16","graphql":"^14.0.0"},"clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"serverDependencies":{"aws-sdk":"^2.438.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.6.0","@types/aws-lambda":"^8.10.25","@types/aws-serverless-express":"^3.3.1","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-router":"^7.0.40","@types/ms":"^0.7.30","@types/node":"^10.14.6","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.4.8","aws-sdk":"^2.449.0","aws-serverless-express":"^3.3.6","body-parser":"^1.19.0","express":"^4.16.4","graphql":"14.2.1","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.4.0","ts-node":"^8.1.0","tslint":"^5.16.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.17","typescript":"^3.4.5"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"d539c84e4f539746886797dc55f4946c0b901876","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.132","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"dist":{"integrity":"sha512-9CRNXfLb5mUk3aRd0idcpPIR+BDPv7h84teZPTmVHUG29kYvvqw1zWDx95jUXhPC36dnkkYgLtGcfHXiacX9cQ==","shasum":"7c6ecdbecb7216687510fe4ee4bfde2d37f41918","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.132.tgz","fileCount":303,"unpackedSize":1006603,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJc0DRRCRA9TVsSAnZWagAAmqAP+gJNGysfghITCdcByIFV\n1Q2v3GvydfyfRr28nX2HGO8ELKhKq19Fm+u4Oyt5N6yNHeEtDHd4js7sZfQ9\nECJRYRW3QgCXbphtcAySvWM2/GvztlRhwgRRHh6IueN6I8HOEM6glSEsUPNQ\n8OCJv+gSIsvGkiOosCBPdiVJv+t89YxPA0Ko3O+4u6i4CvLG7rww2o1/UraF\ng0z5FkneB+U/IovoknPODnw1FFQbKgGU0tIFrmrW2UVMla8DddPDsCK/ArvS\nMbAAGADa4QOwnjtZWlbGQ6bVEpsmt7FZpc4Ko58N46r5lzGH06kzNA7kj1NL\n0ixlnTMMGGV1i/icCCV7WU277TZRnzZoS933c/g4Pnn1yzdmKzIBoe0vCMte\noz5ca9KXO8I0V0goK74TstX/7CkhY2N6dHZXXDVjXQ3xZr99nkVmULu5VJIG\n3a7Zryhl/f293++K1Zqcru9g2kVWp7tQHlbQgsEnN3gbuA6e/DiXhRUnQfdn\nAF8S9e6VkgN5LX7M0+jim9FGyALqt+T+EqKIyYOytWtE01qX40adEbzQCtp4\non92atscFNF102LKggEkOBVPJSCQYZ2qm71/ENgfTJw23gF3E5ErvJ3F47Y8\nSWVOkTwuD/f+zMWV5+y9kMSAN0R6EiL1acdwFYVPUZralUH/DzXlHdYTIyrN\nwOXR\r\n=bGXu\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCHEndlewx29xSIzOIvx1vWoJAdh1ema2c0ptKaEyD4fQIgU5s4RBkIMgIexK3a0mcfqsJCD2EAurnBw4lkS4aA62A="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.132_1557148752438_0.7702754555007447"},"_hasShrinkwrap":false},"0.1.133":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.133","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","dependencies":{"@apollographql/graphql-playground-html":"^1.6.18","@creditkarma/thrift-server-core":"^0.13.6","apollo-server-core":"^2.5.0","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.26","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.3.0","jsonwebtoken":"^8.5.1","ms":"^2.1.1","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"typeorm":"^0.2.17","graphql":"^14.3.1"},"clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"serverDependencies":{"aws-sdk":"^2.438.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.6.2","@types/aws-lambda":"^8.10.26","@types/aws-serverless-express":"^3.3.1","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-router":"^7.0.40","@types/ms":"^0.7.30","@types/node":"^10.14.7","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.5.0","aws-sdk":"^2.463.0","aws-serverless-express":"^3.3.6","body-parser":"^1.19.0","express":"^4.17.1","graphql":"^14.3.1","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.4.0","ts-node":"^8.2.0","tslint":"^5.16.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.17","typescript":"^3.4.5"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"bddd09a4375669c47fa6bf92a3dfb42c4de72007","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.133","_nodeVersion":"10.15.3","_npmVersion":"6.9.0","dist":{"integrity":"sha512-eSnlVKury1rWHOaasFKghxnN9+ennGfys0dE+TM72fxYqs8qzumVutGU7heVeu8UQHVQsZs3UJpT2bBXahI8mQ==","shasum":"fc463e9e26dfc1389b4c35c85009c65df5cd52e3","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.133.tgz","fileCount":303,"unpackedSize":1006606,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJc7OwKCRA9TVsSAnZWagAA+GsQAJWfF6uFfEZpF8iYDWFj\n+tJedC/dPl4zFBDA6I9tofRLIm3QweTFDclg6iyfOthA2fA8A4DgfMnbCENt\npPC08vrV28C7+RARYJhF3u0Npi9PECxaAVIMF+GDlVykUxu46y4oBkY0JGTQ\nXwGxRCZs535fX5GKHgtAmZmpnYy87Cl6eD1IdlENt2K2SxbEBvXhn6jdZ2D/\n5v1cqFOo8tqqq1K1tQ3oHjkCQZgpy/sZ21RF7HAUWjr19U7HSFZ1LZeT7T89\n6ge99cL/hjgIOMGg0wTOa8nYJnG0kmmToW7em6GvqVe3FXlsPTYRkUEB0ssp\n7WrTmRIC8KcESGDCvqI4uE/Am3F/SywC4kMiylvVXOnNxZ755WI1wAHF0hbl\nmyHURSjnb4aM7o8vrcT1lomuTg0XKXHYlLA+QUX3NLRNyH5+u8AYMv74gIlt\nFkEL6bgIRUrbEzX7zYBQGBqLiH32Dr/lmp9KaAppRv3l0uaDFPIZfDy7dQfM\nhN4oGOA7XiQpqdZcyRvtq/sWEhH5rgQEl8DkwfBON/r9pJKkLu7q3eLFBeyO\nNi87UbERfvmL5DlQ+Ehc8qpsX7o+K1EL7YN2MusujjqFWwdQEcCIJ9hA8fw3\nPI2qgA1GdVhn1SU+hzvAvzYLW0FYxZ797ZAYv3q/Y1gPlhY44UZ5OzG4HdgT\nqgtw\r\n=iQS9\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIClX3LAPlommtjtAAFNfBjdyv+u8ccKEFp4rtoNBcFe0AiEArhusNM6c8Cqf+JyrrJnFQUFu+B0MnJAWEmBYY2SzwAc="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.133_1559030793530_0.252257679421094"},"_hasShrinkwrap":false},"0.1.134":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.134","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","dependencies":{"@apollographql/graphql-playground-html":"^1.6.18","@creditkarma/thrift-server-core":"^0.13.6","apollo-server-core":"^2.5.0","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.26","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.3.0","jsonwebtoken":"^8.5.1","ms":"^2.1.1","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"typeorm":"^0.2.17","graphql":"^14.3.1"},"clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"serverDependencies":{"aws-sdk":"^2.438.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.6.2","@types/aws-lambda":"^8.10.26","@types/aws-serverless-express":"^3.3.1","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-router":"^7.0.40","@types/ms":"^0.7.30","@types/node":"^10.14.7","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.5.0","aws-sdk":"^2.463.0","aws-serverless-express":"^3.3.6","body-parser":"^1.19.0","express":"^4.17.1","graphql":"^14.3.1","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.4.0","ts-node":"^8.2.0","tslint":"^5.16.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.17","typescript":"^3.4.5"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"3dae8300bd635f1601ec34f9aebb8a8eae59eddb","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.134","_nodeVersion":"10.15.3","_npmVersion":"6.9.0","dist":{"integrity":"sha512-Na3R9EEZfn1G6AtJ6Shm+dTbjAHrBONmy/5Gs0fP0GVgshWruMRKKUl/L4vsPUcjJh5cODcyW+cyi7Gaq8iNzg==","shasum":"d9a336a6321b8e0ed56dbb946679e1fd792f39d1","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.134.tgz","fileCount":303,"unpackedSize":1007446,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJc7QTMCRA9TVsSAnZWagAAyYYQAIyEd9sXr//NFDXRQIEG\nRDpKRyH0brECH/xXkpxBwxJRuXkXH26y7kyLvM9BkqktUPv1eGHbCedUSd+E\njgeroCaNXqW7mNlbJpB9g7ZdrYykGSe/YqtQvLI1MBwjo4U7oedIgya61iDg\n33Aor725b2F6G+goiFVNO8EMsgDWgcOaJxEdk8UsQLGoqfcK9FfLPqbhfQO3\nUEErTYa5SEDjgwh2xcEzMvOGnCFgOQ3RJxHO6zluD6h5ZXwzZE1N906poIb3\nR18++VV5ImnNbkVvCekxp4zNTTiFLTzcNHKZR8PVaDnG0wdskwrS/Y6UxRJT\nEK+ocwDdNckqpAldJ/tg0ClsD8Xiw2npEpDvohUsMHjdnCvtmJMVr1oNOWZ2\n0g96Fraw5mhxBWPEHflEKcBLhbQ0kfavLV61mWbd/ZoaVbqJ5QJEaQNh/Iul\nZYbWx6ITIdnsvKyfKZoA7ITlLC55pKF+AWMz9fTS4lHaAPlsrcJWRtHnIh9Z\ne5IAazIJGUafWTezfSrD7KCrfMbCoTAhbnQJlv+DmuVQ6GIXnuZ8QkAZBWpZ\nRv/TCpwSa+vA9ttTaGrfxsu2ChU6ReQGTa0BQqmivFx15gE+fVqDPWOfpwZ9\n0OgRwn8LhxDhLLDGIkrUWKR6DNrPMC/1j4xrXx76AACxFKpBvv1UF3ryvMMG\nCMwx\r\n=b3h5\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAfhlq9RE0CdKhroHkr9kEZ9Ic7lmaVZyjeVchHnytpiAiEAiPTmitHdB2NxCWsOzvW6rsMnh37dOtwyI+KG64f+WFE="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.134_1559037132136_0.13923586074880911"},"_hasShrinkwrap":false},"0.1.136":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.136","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","dependencies":{"@apollographql/graphql-playground-html":"^1.6.18","@creditkarma/thrift-server-core":"^0.13.6","apollo-server-core":"^2.5.0","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.26","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.4","graphql-type-json":"^0.3.0","jsonwebtoken":"^8.5.1","ms":"^2.1.1","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"typeorm":"^0.2.17","graphql":"^14.3.1"},"clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"serverDependencies":{"aws-sdk":"^2.438.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.6.2","@types/aws-lambda":"^8.10.26","@types/aws-serverless-express":"^3.3.1","@types/body-parser":"^1.17.0","@types/express":"^4.16.1","@types/graphql":"^14.2.0","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.48","@types/koa-router":"^7.0.40","@types/ms":"^0.7.30","@types/node":"^10.14.7","@types/uuid":"^3.4.4","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.5.0","aws-sdk":"^2.463.0","aws-serverless-express":"^3.3.6","body-parser":"^1.19.0","express":"^4.17.1","graphql":"^14.3.1","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.4.0","ts-node":"^8.2.0","tslint":"^5.16.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.17","typescript":"^3.4.5"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"cd7bac5171826493d1e82f71d02e5c95539247f3","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.136","_nodeVersion":"10.15.3","_npmVersion":"6.9.0","dist":{"integrity":"sha512-/B9Tl0r0miXpH0L9TAGVSom06rFkRvJ0dIxZLJXKbspj1+zfa0ZdFrtNzj0vJCg+MlpqRZ/+YO0Wp4xDzP+vtw==","shasum":"3b386d75834c721d58296fcf46d9ee4d47dafd58","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.136.tgz","fileCount":303,"unpackedSize":1007553,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJc7QX3CRA9TVsSAnZWagAAeW4P/3VVBLZ9e3VCm+4VwOlj\nalwC3UAOifAep02A6aJ/hXlZNv796H6fDpbHRQErFgX2+v7EIucgYegSYYF6\nZFzTFZL5TXuaXwnzsgCOPP4KMSuLD8GtvtnJqD9QHuoWgr4mLLV0+NuW4zXU\nBA9uOINAVFOy0QyuVaj0QE0DEVED4AwtLdJ912aDBsvBU469SoP7S0tlqM65\neHn8pnDP8k4jmspdGncuCI5jadac/CiQPQpH8rzWGZ7elrnpeDT0OJ4D79xp\nIcOXJgAmjL3rcAuwBlbQxfoNMoERouzGU/vnRic/BrtsbkaR/Gacn4ouu3UL\nbJJGyXroYmtE57dlqmx2cgUaEEyAEngoa949UD/mBFXmZTGwSPV8pm3MA61d\nLn1/uRFWjA4LCy1VgJ52RDX4KVal+Ek5kkG7xYLGpBK62QqH3xAhpOfOeTcw\nrTeaC/UhPF53QCWTduTeSekAl2d9WUGNODwFdh0E854qty1LalQSwk6VpLWJ\nwnxwIfrXRqugSNSzofYbqvxyOrWqL9aB3HvzXKqAjjXDitl9bRif1n3ZHK9j\nf+C1QEEOZofFgIrDQmTiwTQB9H7Pi1iCUMlCg0R9D8vnW04HSFk2vRhnC4Yh\nhDdvdBvyIjXAt5qiUtwpfPOeeDV2HvS08bq7wD/GQYv8zNglSLffCB//3BSo\nGbnI\r\n=pivO\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDgMrpja9LOGsf7YWxyijytG9yR3tW2xyCbCgIFOYuyigIhALVRGIiafL3uqL9V2dpNkVN5f9/08miNbchTbaZUKsoa"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.136_1559037431057_0.351863249443364"},"_hasShrinkwrap":false},"0.1.137":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.137","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","dependencies":{"@apollographql/graphql-playground-html":"^1.6.24","@creditkarma/thrift-server-core":"^0.13.7","apollo-server-core":"^2.6.8","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.26","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.5","graphql-type-json":"^0.3.0","jsonwebtoken":"^8.5.1","ms":"^2.1.2","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"typeorm":"^0.2.17","graphql":"^14.3.1"},"clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"serverDependencies":{"aws-sdk":"^2.438.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.7.1","@types/aws-lambda":"^8.10.28","@types/aws-serverless-express":"^3.3.1","@types/body-parser":"^1.17.0","@types/express":"^4.17.0","@types/graphql":"^14.2.2","@types/graphql-iso-date":"^3.3.1","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.2","@types/koa":"^2.0.49","@types/koa-router":"^7.0.42","@types/ms":"^0.7.30","@types/node":"^10.14.12","@types/uuid":"^3.4.5","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.6.8","aws-sdk":"^2.490.0","aws-serverless-express":"^3.3.6","body-parser":"^1.19.0","express":"^4.17.1","graphql":"^14.4.2","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.4.1","ts-node":"^8.3.0","tslint":"^5.18.0","tslint-config-airbnb":"^5.11.1","typeorm":"^0.2.18","typescript":"^3.5.3"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"a8a12b15f59c837608c34c1f16fa5a60239fd766","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.137","_nodeVersion":"10.16.0","_npmVersion":"6.10.0","dist":{"integrity":"sha512-IvzBuVasBR4p3coes/ssIMq+6VEY5k+RtpXNXwZUzWVlDIAnNgI+Ja73HE9LRQtBsm7jnxAxvJ/uN+nlqE8l1Q==","shasum":"31d7a5d1087a091053aed569c09a7e2741b5e816","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.137.tgz","fileCount":303,"unpackedSize":1007361,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdJZ4zCRA9TVsSAnZWagAACVoP+wWlHXuaPfqC+blzHtDM\nelr2nU5dlK9EsOd06scpFeYu+NT7VJq/ivrvlpxY27ALuPiBXPJ6X6w70iIm\n295v9nUs8dkZXdTuN08wHvrOXQStun0nWtIwsX3fpIJ0nKnCs6bPDt1TSBUT\n9A0d4NHkO1NdVpSy9GTEd/D6z7w5jN5hT6VQmHX6Eu6vA/P6KPVbE+Qnkrxe\nap61y2DcguxrXRMPJw0hntsqvoMdCPuIkqHixcPEMEvsFkglGjHhEC0MTrVX\n5xScye0lJavX1CFQxXtKDAUK3sR/znzp1hQ0tHWCCukTktjhm5WYJQ2lZ9I5\nA3D2FG5Q1uRHI9fZ5B85jkrGvH7tXbytY7D0givTxh6YaAZLv39pRyfPoqKU\n3AeAwes6yBqTI4aY+NSJJIc447VZSyvVFxf/Xm/zZHzFboLHOiTDEfnWw31s\nfp1nbA/EvGfe49QQzdOFIZrXcxZW+xH5mDSp6sikFZJpx9AYd8fYrzP3T1qC\n7KKzmn7EIdGMa01Hz90+CaGsfuKY/oSL9jDL3Pt8uuQl5MsDLFIGWNJeidTb\nqIwjEF+phkVtyk27ylNlIfQWyiAeBc5uk24S1HJqGsgdwbcM2TpGKbbJoOWN\n2OwLcmL/QmlsImjcXMhifLbxqsF2EEfWesu26+nwz0pdOpjsvBr19UKM6/Wn\nzQ1c\r\n=+3wb\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIG+DQrc+iz7OmS9B8PACZ7iTu3PwnuEwUKe13sMm3TvVAiBX4OQ+8TaCOEJR2rcpcfo/O2eGxDweodeuFALQ+a7SRg=="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.137_1562746419224_0.11007510889597127"},"_hasShrinkwrap":false},"0.1.138":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.138","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","dependencies":{"@apollographql/graphql-playground-html":"^1.6.24","@creditkarma/thrift-server-core":"^0.13.7","apollo-server-core":"^2.9.4","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.26","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.5","graphql-type-json":"^0.3.0","jsonwebtoken":"^8.5.1","ms":"^2.1.2","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.2","wtfnode":"^0.8.0"},"peerDependencies":{"typeorm":"^0.2.17","graphql":"^14.3.1"},"clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"serverDependencies":{"aws-sdk":"^2.438.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.7.6","@types/aws-lambda":"^8.10.33","@types/aws-serverless-express":"^3.3.1","@types/body-parser":"^1.17.0","@types/express":"^4.17.0","@types/graphql":"^14.2.2","@types/graphql-iso-date":"^3.3.3","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.4","@types/koa":"^2.0.50","@types/koa-router":"^7.0.42","@types/ms":"^0.7.31","@types/node":"^10.14.19","@types/uuid":"^3.4.5","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.9.4","aws-sdk":"^2.536.0","aws-serverless-express":"^3.3.6","body-parser":"^1.19.0","express":"^4.17.1","graphql":"^14.5.8","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.4.1","ts-node":"^8.4.1","tslint":"^5.20.0","tslint-config-airbnb":"^5.11.2","typeorm":"^0.2.19","typescript":"^3.6.3"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"0beb8bd53b1221e50055168465f92940e639bf50","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.138","_nodeVersion":"10.16.3","_npmVersion":"6.11.2","dist":{"integrity":"sha512-27z7qoPh/4mdUoDfWi76aH3vhJpUq5ttkoZ2Asw3hKFtFEXGNiTFFgW/aS2Zq4v340WWTAytPPrgi1hTLqGGVg==","shasum":"fd4bf1ae86933370b7b8f6990651fcacef4e99cd","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.138.tgz","fileCount":303,"unpackedSize":1007736,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdjLTRCRA9TVsSAnZWagAAXBwP+wXbxTMeo0/tkGDusqDd\n2LeNhwPSdmX8oMR7ZmRgwBLLXLWhxnhGgG77V4LYgCh2NYaFn8KURfYlnj78\nycTxNombzl0+bF7vB+yOc02GAWpyaFwyaC9vC/PewdErwupz+PJLjEamVETf\nQouTiv1xSnobvf1AbD3aXVja81bDrQ1U18hgpHqNWkGq4bX6otjczCi1m4Uq\ngfX2/IDVOb0456liaUT0EJwhRy+fX6WyxJB7EV4iTuhBqXY9TsyMYNwKf4bj\nYQd1JNvhgTiht14BgUao+cToCAH1uBzHx5nat2S6qA4M1qHQzutmPWY5BNHA\nsAaWiFhZEdnZv745Qh9BAJ1t+TaocqfzAjhikUoqhUYJCnl3bkJ3Ky2CD0uu\nskpc1p2qWLL4pqBQ2MskPrGoXiqBOgzBqHik0niJEhnJPnDP70c0I8Tcekk/\nhkRxuQRzRR26B0f7601TFglcoVcAEL5rqH4/qBIc6bQdMP5i9NnltK+pr3A7\nEm8UB6bYnKGqa/GuxIbUpoeqOnAm7jX18F5AGBoIFXA7fMCyuuL773Zb4t6T\nWEi56YKmrzQtCNdh/G3zQn09v/wnlXhfgUwM0A9VD3YheKxErLLyxOa9C+lS\nrSGuOirT9l1qZhjKWf/X4c7fUgS6AF6qF1UNC15pBWzmCzlnNfchkvzibN23\nZmPV\r\n=Kc+s\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFuv1o9lbMeyTJtI8zdKcLII6hrseL71naqd88gxtuLXAiA3aXkxSUlbBO6MVVI6MIpR7PipaOe1RIb+BMdFpTrbpg=="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.138_1569502416868_0.7315328981005196"},"_hasShrinkwrap":false},"0.1.139":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.139","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","dependencies":{"@apollographql/graphql-playground-html":"^1.6.24","@creditkarma/thrift-server-core":"^0.13.8","apollo-server-core":"^2.9.12","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.37","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.6","graphql-type-json":"^0.3.1","jsonwebtoken":"^8.5.1","ms":"^2.1.2","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.3","wtfnode":"^0.8.0"},"peerDependencies":{"typeorm":"^0.2.17","graphql":"^14.3.1"},"clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"serverDependencies":{"aws-sdk":"^2.438.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.7.6","@types/aws-lambda":"^8.10.36","@types/aws-serverless-express":"^3.3.2","@types/body-parser":"^1.17.1","@types/express":"^4.17.2","@types/graphql":"^14.5.0","@types/graphql-iso-date":"^3.3.3","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.5","@types/koa":"^2.11.0","@types/koa-router":"^7.0.42","@types/ms":"^0.7.31","@types/node":"^10.17.6","@types/uuid":"^3.4.6","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.9.12","aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","body-parser":"^1.19.0","express":"^4.17.1","graphql":"^14.5.8","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","ts-node":"^8.5.4","tslint":"^5.20.1","tslint-config-airbnb":"^5.11.2","typeorm":"^0.2.20","typescript":"^3.7.3"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","gitHead":"7286af2fd5b7ae3f1e466d5a7ad7d4de31d01273","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.139","_nodeVersion":"12.13.1","_npmVersion":"6.12.1","dist":{"integrity":"sha512-ygVZIvDZjX9Ipvjr6hTCXsQX8XeWBycAjq2YGHQACntNG61gg10QIdhflhDyv+VWuribv1I2dlnQYdrHofVbAg==","shasum":"c52a349848b548db26086d2f6124f4c8d16f997a","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.139.tgz","fileCount":303,"unpackedSize":1008195,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJd6NGOCRA9TVsSAnZWagAAA58P/A34UW0SP9Skwd5FRG8x\n84YY8X0bsIhufK1wD1hHejbSYki2DpqAyXAQGlvTDZqpLuosbHe8ho32zxNm\n6xLQ5xuwGCA30IjMEB2fyYe+1nQ3cIrmCqRQXWT8zEjzolIxzJIoHhGCjs/R\nYEfAQ3eEXygCA/xSKmGO1tiJGyvha8pohnBmEDGpx02pNNMA685xyx0Q1MsL\nxa9T0wScJbE59u8iEW6scmk4DkE8gDBfyVQaaef1GMyS22j8LMeXt+nSvYXx\npKQxCIghvVXyQ8FQN6Gty0EWv4wCJpeaTylbNyeknZn90ynbNxzPZFwBytAR\nGGT95rrUqxa0ct0wmdbPEiKZchpUNkHjedFqghI8Yt6wj7lQW2kHwQ69yhS8\n2ACj8SA2ZsaZIp4JYZi5Kfe7TPZbuQbLCa77OEktSNTVT90ibZWyPjRj2Zr9\nR0EV4FIOpFst4sPPLzvlSxIcTuZ9VtgZO2kG+77ibskNEfHtKBj9+xZ1MOq2\nyUq64jm0cpPHdSjPV3U1udomXacVDN0HfobZt06ns7MaON7zDZ0NKCgbyVFj\nDmTuU7hKfXKLbmDDEF7M/XHOBLRG5yOh0cen4HDG2M/xU1FUWxFNQfWacyQq\nzhwmI2nWyLBPz3ZGZhYatlHXUJjMx0htvkUa2nVnsd5gRvmMiLPDTspnkpki\nV1xw\r\n=ZZye\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFF2coza1Bf3cUhDE+HEOJDp1Orn5okqJBy2BFQB3WecAiBM1DT4ibSvq0JEPf7/0XsKDytCC7Wl68wg+9ugM2lT2Q=="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.139_1575539086470_0.35817860008040725"},"_hasShrinkwrap":false},"0.1.140":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.140","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","dependencies":{"@apollographql/graphql-playground-html":"^1.6.24","@creditkarma/thrift-server-core":"^0.13.8","apollo-server-core":"^2.9.12","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.37","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.6","graphql-type-json":"^0.3.1","jsonwebtoken":"^8.5.1","ms":"^2.1.2","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.3","wtfnode":"^0.8.0"},"peerDependencies":{"typeorm":"^0.2.17","graphql":"^14.3.1"},"clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"serverDependencies":{"aws-sdk":"^2.438.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.7.6","@types/aws-lambda":"^8.10.36","@types/aws-serverless-express":"^3.3.2","@types/body-parser":"^1.17.1","@types/express":"^4.17.2","@types/graphql":"^14.5.0","@types/graphql-iso-date":"^3.3.3","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.5","@types/koa":"^2.11.0","@types/koa-router":"^7.0.42","@types/ms":"^0.7.31","@types/node":"^10.17.6","@types/uuid":"^3.4.6","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.9.12","aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","body-parser":"^1.19.0","express":"^4.17.1","graphql":"^14.5.8","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","ts-node":"^8.5.4","tslint":"^5.20.1","tslint-config-airbnb":"^5.11.2","typeorm":"^0.2.20","typescript":"^3.7.3"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"6361ed0ce07e8ca4da5fa52d9b41a9c5187a3e28","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.140","_nodeVersion":"10.17.0","_npmVersion":"6.11.3","dist":{"integrity":"sha512-FcF/Dp8qojrO9r8W7M9nuQwo9fN6YT1W3EDYgUEQcwFQ9WIpWnVy6uaei/G8Vt1dYdxRGH5PJM0FTcZH4o56Cw==","shasum":"0a281e6fd5c265e48f271efd7d5d35f7016755e2","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.140.tgz","fileCount":303,"unpackedSize":1008858,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJd6OjvCRA9TVsSAnZWagAAENAP/jn0Iem1YrK/egQF3ws8\nZkfTur4S1dAcBGCQ3Lvclmbhp3H4inaLhZmioO8+J5Sxr/I/xZjlmjUFeeFB\n8wKy0MliZRTidPCpHHvV9W+sWhWpnK+a81yd8cfF2brmU4OcvF/cuHZASOUF\neilDlIrVDnWpAaBWaROZWVvF9ljlZ/2B87NY/2xACMOao9IZHjwaORs3iguV\ngyaxhVxreJHPJZvMBXN9YugIwTiTr3nJeKkSceEzf9Eh4044hLfyL5vlK8hK\no3AbtwgdEfWe2ipze2dpvBY8/Vrn1x9vc0iOQHKq8hJVNlx+F2FEFirjMMz5\nN9CclGHB0Qpbqkj/rbXnXgSXx/RjgzYMrTvLEgDnRAiesznjT2gFyDxlxUQC\n0NX1RrCszwUJOtYBypBdnlj+7pQfmnHmVWx2w2sub8FX0HTklcFGKj2t4gO+\n8dWibt5KI88fvIz9YE/yu1IdygZWmB8nDDEMvdBVt9f4qA9Fhw30jy0rC1rC\nVNADR9dRyWA0CCFW8Q+ozOM09taPyfjNRUKZxn11+Ncovd/3EbMH8Kr4RXKp\n4mQFnyjnSYTXS/99ETchBYqOq3qKLScX7hVjYRhO6F4UQh1Dx97+LWnxcBQs\nwwLpII2gw3amWfIkyAKRDj6Bgjr3TWS0oxDiVNFypHYLhomXVYHbHH9wmtqG\nziIj\r\n=eUOC\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIC6fYnRoqolKwAWJ3xGmy7rHD6DYashHRnD2kjTgdKUbAiEAnt3LgLOnNQmpqErze+r++DR2rSBUtZDHcyEOPSwCu20="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.140_1575545071418_0.7965025872511688"},"_hasShrinkwrap":false},"0.1.141":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.141","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","dependencies":{"@apollographql/graphql-playground-html":"^1.6.24","@creditkarma/thrift-server-core":"^0.13.8","apollo-server-core":"^2.9.12","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.37","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.6","graphql-type-json":"^0.3.1","jsonwebtoken":"^8.5.1","ms":"^2.1.2","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.3","wtfnode":"^0.8.0"},"peerDependencies":{"typeorm":"^0.2.17","graphql":"^14.3.1"},"clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"serverDependencies":{"aws-sdk":"^2.438.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.7.6","@types/aws-lambda":"^8.10.36","@types/aws-serverless-express":"^3.3.2","@types/body-parser":"^1.17.1","@types/express":"^4.17.2","@types/graphql":"^14.5.0","@types/graphql-iso-date":"^3.3.3","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.5","@types/koa":"^2.11.0","@types/koa-router":"^7.0.42","@types/ms":"^0.7.31","@types/node":"^10.17.6","@types/uuid":"^3.4.6","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.9.12","aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","body-parser":"^1.19.0","express":"^4.17.1","graphql":"^14.5.8","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","ts-node":"^8.5.4","tslint":"^5.20.1","tslint-config-airbnb":"^5.11.2","typeorm":"^0.2.20","typescript":"^3.7.3"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"f01a68b56b1abb5de21953b3e806cb2f61b00ac2","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.141","_nodeVersion":"10.17.0","_npmVersion":"6.11.3","dist":{"integrity":"sha512-qj3UN1b+40QBu2qSeIcRBJHtpFmssm4npDFZPop1cfftoLYP8yYoESrsgZ4nVt6SG2Sw0gnwAVNiUc7I8Shohw==","shasum":"88aca59a10291ecb0ed5eda2e2d70ee7e0a6e905","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.141.tgz","fileCount":303,"unpackedSize":1009805,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJd6O6ZCRA9TVsSAnZWagAAdN0P/ji4yNX/X0FSwCmC/uJG\nlRhdpY/Zu0LyUYvkDDNaQ/Teo3InX7sW97XUd7p0o8BEi2NANAQA0LyaM9G9\nyh0du6r09X4wz6qiPa7yHQsfVSAWKWUkEpN9iRV7z53m/0GJmmFPmWrxj65K\nD9juIiST9UNzXJD5gqREcgLWGdvrRfxHzCzvB9PjHUUduLtCidXQtmRbPCgz\nsjauya4vdXjTzZaq0jjJlUQXgWqLGny3EAC3X35mrWETOtoBBcRwSmswXm5P\nBJ6DNEbN0NC0lv6hQrN1qEU0QDBF0WyU5AQUCTrONPef1JJQ3JHovX/XkXNo\nV4CsFXsQXwIfrICvn1x6Bb3DN51fnl5Shdlb2SGfm+Xv4Kcs0UR8TGrsydrA\nVyRAyY2PRXbCZnVTykHy6VveWF2BLH9BddTPlKxDi9Oz+iRs959M3FYv/AuI\n2lgNrRrgl4k0Xlvg3eVJwZO+pPZA+wXZXRG8AeIpIbDRiiE1jch/+7mKJ7QE\nYm4jU60EZSMFQtsECHUj1g/BKttCL2XpHISwWRz6HnaLoXmoj8d8aKlbORPi\nChXiHkz/QSRHB5DcmicHKp2Y9rHkfekD8hTvdSMr9fcCPyJhn0HtMrhWaba+\nBdfdfM+Wl/C7Q/J31EloyjKLKg+s3h4Gnqlwy6Z5Sm4+ynpaDGr9zBOWeQ+2\nNalN\r\n=yyng\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCID1UX6KxlArkVOpzy4Gu3LuvchvSZ6mTCRrrPdYYpp77AiEA1T6Q8gKkttRz0uYYjBGTxZaCJlx3qR6WB0g3fn8R+aM="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.141_1575546520669_0.6559644477160467"},"_hasShrinkwrap":false},"0.1.142":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.1.142","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","dependencies":{"@apollographql/graphql-playground-html":"^1.6.24","@creditkarma/thrift-server-core":"^0.13.8","apollo-server-core":"^2.9.12","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.38","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.6","graphql-type-json":"^0.3.1","jsonwebtoken":"^8.5.1","ms":"^2.1.2","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.3","wtfnode":"^0.8.0"},"peerDependencies":{"typeorm":"^0.2.17","graphql":"^14.3.1"},"clientDependencies":{"graphql-voyager":"^1.0.0-rc.19"},"serverDependencies":{"aws-sdk":"^2.438.0","aws-serverless-express":"^3.3.5","koa":"^2.7.0","koa-router":"^7.4.0","raw-body":"^2.3.3","body-parser":"^1.18.3","express":"^4.16.4"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.7.6","@types/aws-lambda":"^8.10.36","@types/aws-serverless-express":"^3.3.2","@types/body-parser":"^1.17.1","@types/express":"^4.17.2","@types/graphql":"^14.5.0","@types/graphql-iso-date":"^3.3.3","@types/graphql-type-json":"^0.1.3","@types/jsonwebtoken":"^8.3.5","@types/koa":"^2.11.0","@types/koa-router":"^7.0.42","@types/ms":"^0.7.31","@types/node":"^10.17.6","@types/uuid":"^3.4.6","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.9.12","aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","body-parser":"^1.19.0","express":"^4.17.1","graphql":"^14.5.8","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","ts-node":"^8.5.4","tslint":"^5.20.1","tslint-config-airbnb":"^5.11.2","typeorm":"^0.2.20","typescript":"^3.7.3"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"6a5104b39b0a7bac86f0906791ee6f645402f188","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.1.142","_nodeVersion":"10.17.0","_npmVersion":"6.11.3","dist":{"integrity":"sha512-pRr0Qhm6fjaE5KwXdXJ3uKYBJiciE+74YvIIhQB0oVefOFozVTPfhntx32sgToKQ4HcGvqj+mdBOwujmULuxjg==","shasum":"2b224ae27a503867c1d3021dceaf02b1a3e5c834","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.1.142.tgz","fileCount":303,"unpackedSize":1010707,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJd6Wa2CRA9TVsSAnZWagAAEn8QAKLiS1RIdLpoEjIKKKo4\nubwhzQA6Q9qY6dRKzX1F/aCYx48Q1aXV1s3cTk9b51OfM04rratYCAuIJOH/\nKba3ueX4eHZIGXHCMI7vA+/w8TIhOgw5WwSh98FR/U3unFQ/K+jUB13kFI89\n/tSyTvAu3Sw61EHJ4kYqzwm3zSagDJxiQrMmEESFOoCH/kDHKNFXZ9kAaZNt\nIdXcijM6uHI9Dl+uF0AQsk1Iu5R2z3jeFr40m9Cl6sZE2FO8+BDHe8bvYA9M\n27yfKMioPWLrr4jmfqFO2UP5nTYSUNqE7lFk7KnPUBYos5c3RzmEPiSAQJvh\n9uSlLZl94TSC0TjGqZFUp1cwsgNv2kOdcap9rxtPwWoTaLnGCbiqpDDCK1Q/\nX31/BUNGtZtV8DvEfTE6skr5M6UFgpxPJ38hgB9ZXMUs8rJ7irKyR0ErT4jG\nywVimktGUfzBNmCwufjoanfCOgR7jd6H+ZSKptm0nYuLYNxDstMpBbFnRGB3\ncRGS0+Wp08Ez3WnRwxuq1U+6z5yRt/4N4khOSwdEbh+IH4jCugIlwj3jCQOU\nbUVbQI5y5602xhm5w7+2d9lgFTRlVBUDQ9RCgeVchF2lImqnwyw1fhgXOfos\nz8lPHVekGIDExqrxTNAwciaioQXQF3DFBVyCzIA3RSjBGLVn+sEp6UAXAXcT\nDqjX\r\n=8vtx\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD6BVwhMjG/TpJlpK339biVDjFSPSBlXA+qVe3u0LDwSQIhAM3pcJ40UVGgr7Mlbl43Jcj2DyMVk/wYY94BMS2mB9TV"}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.1.142_1575577269997_0.3896617099602184"},"_hasShrinkwrap":false},"0.2.1":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.2.1","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","dependencies":{"@apollographql/graphql-playground-html":"^1.6.24","@creditkarma/thrift-server-core":"^0.15.3","apollo-server-core":"^2.9.13","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.38","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.6","graphql-type-json":"^0.3.1","jsonwebtoken":"^8.5.1","ms":"^2.1.2","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.3","wtfnode":"^0.8.0"},"peerDependencies":{"typeorm":"^0.2.21","graphql":"^14.5.8"},"clientDependencies":{"graphql-voyager":"^1.0.0-rc.28"},"serverDependencies":{"aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","body-parser":"^1.19.0","express":"^4.17.1"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.7.6","@types/aws-lambda":"^8.10.36","@types/aws-serverless-express":"^3.3.2","@types/body-parser":"^1.17.1","@types/express":"^4.17.2","@types/graphql":"^14.5.0","@types/graphql-iso-date":"^3.3.3","@types/graphql-type-json":"^0.3.2","@types/jsonwebtoken":"^8.3.5","@types/koa":"^2.11.0","@types/koa-router":"^7.0.42","@types/ms":"^0.7.31","@types/node":"^12.12.14","@types/uuid":"^3.4.6","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.9.13","aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","body-parser":"^1.19.0","express":"^4.17.1","graphql":"^14.5.8","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","ts-node":"^8.5.4","tslint":"^5.20.1","tslint-config-airbnb":"^5.11.2","typeorm":"^0.2.21","typescript":"^3.7.3"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"44060d0480e46c2cc73fa7642d59a3834dea8204","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.2.1","_nodeVersion":"10.17.0","_npmVersion":"6.11.3","dist":{"integrity":"sha512-uHWzxQCy8tX+aSdJz03rRRiNTNW70Ht583q8YGbfPYsP22OPtn8rYz9cHJ+xJ1QZGNI/AZIOyWpz4zizkqegaQ==","shasum":"7829364374423bf07f4b6e9bd07b401afe7f02b5","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.2.1.tgz","fileCount":303,"unpackedSize":1011074,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJd6hrNCRA9TVsSAnZWagAAZOYP/1rWRLNDm+wWIxMa9+rZ\nfhfa4GCHmJ46P6HOIAXscqi2B3eubuuFeW0FPsakG//hwkJgHPGLu0B+4uUs\nlIIaSoMt9sH62a9it7eIuT4v13nWE45Kj6GP9dnU88G61U9ZB2kTYVe7K+u8\n/NKfpXsMV6F/0ESu95gIDbhBvLXZd7OrwHUmFTVBcYnQC+dNPJMPk4NBHr8I\n0It8i6BgePYzZUwRyzrPDhlLWXcu3SrjzD1KvKndl3Ucjq4Ldfz+eGW/4brV\nfJr0cTtnEOBdKb6Fa1XSmHzLQHVwTqMMiBEb9+XcgOdNHfKfY/ujQNnjb0c4\nd+uIvs/7yHDPITYD2crT+WOsXUGTvHMolNVSU9rIMaTNl8kUSg1HF8PVaILB\nFqh2hCq9CivTwgOAoIVGrGdgo2Id335SJ6so9fYfLKe/O+CQDVi0H8mHDU5C\nle9Ff5nJaFs5rxxft4GFhtm+p6jmyZ7ZuOlIPNamwqPJZa6KHrJ5CKE/9KUJ\np7ZsyiuMlGbWknI59EXU/TxWP6q8Df5gdWJhpGO8zv2FSS71W+NCUmGeHKjY\n5vExwzRd/rhX8YXlnf3v5Qxqt+sOZk1r8/PhlptonXckY9NhUI9wnpGtL9UX\nX+znEY7c6tMvUC/4fSIhv7MDU1mqQ80YRRA2RbdSWnWbtSZ3MGRq+wyuxiQ7\n/87V\r\n=Z7Hm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCID2YaezCsomxexhujghYRu9224bsyHd9ZDD9+XIzDlpIAiEAgAmQltX6T1K4Z27n/BqOCcJV7waHRH5XXAVxLZoIojE="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.2.1_1575623373380_0.7237267239210687"},"_hasShrinkwrap":false},"0.2.2":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.2.2","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","dependencies":{"@apollographql/graphql-playground-html":"^1.6.24","@creditkarma/thrift-server-core":"^0.15.3","apollo-server-core":"^2.9.13","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.38","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.6","graphql-type-json":"^0.3.1","jsonwebtoken":"^8.5.1","ms":"^2.1.2","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.3","wtfnode":"^0.8.0"},"peerDependencies":{"typeorm":"^0.2.21","graphql":"^14.5.8"},"clientDependencies":{"graphql-voyager":"^1.0.0-rc.28"},"serverDependencies":{"aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","body-parser":"^1.19.0","express":"^4.17.1"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.7.6","@types/aws-lambda":"^8.10.36","@types/aws-serverless-express":"^3.3.2","@types/body-parser":"^1.17.1","@types/express":"^4.17.2","@types/graphql":"^14.5.0","@types/graphql-iso-date":"^3.3.3","@types/graphql-type-json":"^0.3.2","@types/jsonwebtoken":"^8.3.5","@types/koa":"^2.11.0","@types/koa-router":"^7.0.42","@types/ms":"^0.7.31","@types/node":"^12.12.14","@types/uuid":"^3.4.6","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.9.13","aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","body-parser":"^1.19.0","express":"^4.17.1","graphql":"^14.5.8","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","ts-node":"^8.5.4","tslint":"^5.20.1","tslint-config-airbnb":"^5.11.2","typeorm":"^0.2.21","typescript":"^3.9.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","gitHead":"d9f315a0cc8382864993bdec72b2e9298eac1d1d","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.2.2","_nodeVersion":"12.16.3","_npmVersion":"6.14.4","dist":{"integrity":"sha512-/EjutGfUZp9ZCLiDLojQCuu4qTJrwW7WWcaEEmO5G8FoWGBRESz6kbVgkLrpb+DTXrnH5L2Jg/DDpZhnJNfHyQ==","shasum":"f1e2b1aff4d7be5dc452412ff83438c825590cde","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.2.2.tgz","fileCount":303,"unpackedSize":1048144,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJexj4ACRA9TVsSAnZWagAAeUUQAIXgM5v8SohI+cPfZHLo\nB2aYkGg0rfy8tS7dQ4+8hkWE14hyj1eKSVSA6SqkoUpK4JgH7lUPdUAjUcVD\naukmRY4ueaRx0yuzLxeXR5CrMcnLyKseEUSHUa1xF1s0juB70oyoo7PHzmeJ\nrU6hGTnta7/wHE4N1fVE6RAHJnz2KxjXj2qU8VuyI9i5fCuQ3Ft14LmwO+xY\nawxLQvy/jVKCHA/kGrfem93jMTBPn+05jibEl5yHpFj5pCpecHNhR0Q1tCQ5\ndybHwxobMkrsN/v6/tH4ibGKgkHyiBdplbflZ7TIkrkc0iFXcJb5fiZ/GSNi\nABYQgIaV+XUPB7c86DrUSt/4FerSDlHc2gIEEbo/C4OG8tlX3P0+y7oeJe1f\nOunU4XywlMEDqqgOKgAbqI+S2FT6mv45Finb4CO35iS75OVQEDqcHkyC5CPD\nximmfSIj52TrNHzWcOjmUZ645gOTCuTSa5cw/uEJwMlzkr9WOVktyOzLPS4P\nd+vKIh0hDmgWNSzVqY4PcxQP6FVFMotGSdJdeqrcfnHDewVKaXi+7JTTGwSV\nzo9T0qFs9eLRL/WXBjxC8LWQjCcdyn1lgAihqkbobkqprd+VzSIUe4qIqfaq\ncN+g2mYjclcA8TSOWlTlJ1iAMg/huXEGri2+y5pmW2Di1Wd9KhudfWJeQIJP\nODPA\r\n=xsLg\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGO/Nqapn72ipD5/OZ7kHBT0miepVfvmk2KK6AZ+NwE9AiA4UEbYb7anBq+rN/zsTLLxF9L5L8uZ3iTUQavxJ4yU0A=="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.2.2_1590050303932_0.4225956377674327"},"_hasShrinkwrap":false},"0.2.3":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.2.3","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","dependencies":{"@apollographql/graphql-playground-html":"^1.6.24","@creditkarma/thrift-server-core":"^0.15.3","apollo-server-core":"^2.9.13","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.38","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.6","graphql-type-json":"^0.3.1","jsonwebtoken":"^8.5.1","ms":"^2.1.2","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.3","wtfnode":"^0.8.0"},"peerDependencies":{"typeorm":"^0.2.21","graphql":"^14.5.8"},"clientDependencies":{"graphql-voyager":"^1.0.0-rc.28"},"serverDependencies":{"aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","body-parser":"^1.19.0","express":"^4.17.1"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.7.6","@types/aws-lambda":"^8.10.36","@types/aws-serverless-express":"^3.3.2","@types/body-parser":"^1.17.1","@types/express":"^4.17.2","@types/graphql":"^14.5.0","@types/graphql-iso-date":"^3.3.3","@types/graphql-type-json":"^0.3.2","@types/jsonwebtoken":"^8.3.5","@types/koa":"^2.11.0","@types/koa-router":"^7.0.42","@types/ms":"^0.7.31","@types/node":"^12.12.14","@types/uuid":"^3.4.6","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.9.13","aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","body-parser":"^1.19.0","express":"^4.17.1","graphql":"^14.5.8","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","ts-node":"^8.5.4","tslint":"^5.20.1","tslint-config-airbnb":"^5.11.2","typeorm":"^0.2.21","typescript":"^3.9.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"gitHead":"f039e8aad66d84bbe1274c4be78601d81782a532","readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.2.3","_nodeVersion":"10.20.1","_npmVersion":"6.14.4","dist":{"integrity":"sha512-rEPlEVIFh73n51hO4/lN9N5boDr10bl/QI0Xpe/B0JU+w95CG3PkxZdkDngyPrOj5jj2AoM+77C+RS3/LSwruQ==","shasum":"c7e5f8508b70e84af3b5257293c90d2f74d880e9","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.2.3.tgz","fileCount":303,"unpackedSize":1048202,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJexmpQCRA9TVsSAnZWagAA5hUP/0ZSylgKONFGUGXpvHWV\nynpp7477ORoZY9tK5RzMnd3N16r69ePm80JHHo2IT+MFG2TCMaVa/e33SIRW\nKtTz7ESIL7k0QWtxPUobxcmaKNRJ2IzlKZDVWRKFyIDmYGRTgYw756CNfvH5\n2wDAXg8wZZDViKlhq6ZjOXyxnJWNUhYdvwfWt+iirKtvjZsabV4cHaRzrDwN\ncrqwFglWjYk4IVE1Y2FXPhUABKgwT5cdRrqnjihezbQwFQSDS7wbQQzg5pVX\nbe91LjmMTETUJYLiZt1pzDgKONU+hJoMzN4gc533FwGYQHLaqV+tBMOR8Ttu\nKySNXic+lofyQAt7DMgdlYo1r0Q2AesqxPJv4Q6B4bKRkAo7kpYnP/E+fmUL\nqMPa0oDvaFYfZ1EpZPL92QDFMpAt//2tGeMwwt3zICjLQTp/YIEDgVGVwvKQ\nts1iDU+aACgMhMkHjeRhoEEFY6+HOMmnvo7keDxFPLyaYO5+qN0dp1BoXmL2\nR8Dhf7arZg9n6Se30WrZBI7ZnRki3bh9VCQn2UrcH6vaZfArf0ftsXWj/Ew0\nkER2uSnySUOoaeu4VErm/QWUxM9bxnJjcX92cks4OxidKH7oWbMf4LVyjoiJ\nZT9k8K8A9py5q6IxmiKIEQ9tBAl9tIfm9TrWyZVvPyrFDUv/5pEI64Py+wSL\nA9Ry\r\n=ATjY\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC60GMyZKKhEFx/lPFZdqCGLOAfeXuY9b3LDjJpy2isCgIgate3cJ0kiA8IRx+PjkGFoQUiA0pJHGLhk0UK8tNOAPg="}]},"maintainers":[{"email":"labs@alite-international.com","name":"alitelabs"},{"email":"kbajalc@gmail.com","name":"kbajalc"}],"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.2.3_1590061647796_0.7811804006515772"},"_hasShrinkwrap":false},"0.2.4":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.2.4","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","dependencies":{"@apollographql/graphql-playground-html":"^1.6.26","@creditkarma/thrift-server-core":"^0.16.1","apollo-server-core":"^2.9.13","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.42","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.6","graphql-type-json":"^0.3.2","jsonwebtoken":"^8.5.1","ms":"^2.1.2","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.4.0","wtfnode":"^0.8.3"},"peerDependencies":{"typeorm":"^0.2.21","graphql":"^14.5.8"},"clientDependencies":{"graphql-voyager":"^1.0.0-rc.28"},"serverDependencies":{"aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","body-parser":"^1.19.0","express":"^4.17.1"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.7.6","@types/aws-lambda":"^8.10.64","@types/aws-serverless-express":"^3.3.3","@types/body-parser":"^1.19.0","@types/express":"^4.17.8","@types/graphql":"^14.5.0","@types/graphql-iso-date":"^3.3.3","@types/graphql-type-json":"^0.3.2","@types/jsonwebtoken":"^8.5.0","@types/koa":"^2.11.6","@types/koa-router":"^7.4.1","@types/ms":"^0.7.31","@types/node":"^12.19.3","@types/uuid":"^8.3.0","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.19.0","aws-sdk":"^2.784.0","aws-serverless-express":"^3.3.8","body-parser":"^1.19.0","express":"^4.17.1","graphql":"^14.5.8","koa":"^2.13.0","koa-router":"^10.0.0","raw-body":"^2.4.1","ts-lint":"^4.5.1","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-airbnb":"^5.11.2","typeorm":"^0.2.29","typescript":"^4.0.5"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","gitHead":"d634d5ce85b8e82295e5f7dc963a53c5509175ec","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.2.4","_nodeVersion":"12.19.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-zuW7VXHvpe36PhpS6eXlP35N5N+DP6cy2XPb0/ZmHeGO9TLLYlSDdNCbudbAusPKuJfwfYtEuJSY91M0qyPSlw==","shasum":"0b40f5b3b3f6b4cb5f8c75c9414af14a8f80051e","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.2.4.tgz","fileCount":303,"unpackedSize":1024487,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfopi9CRA9TVsSAnZWagAAreIP/3l6gKedgsJRm9MuHYjl\nTsx9cliS0AeOln2Fe0e5RSKqbxfg31ExnZYQGGgf+iLFGFGq6RV5tZRZKlyc\n+WZFGUcnHYa93eifqLMoCtiNbAnIfvHNMEyCxaAqwEVWKzik8r9b+i4tvcbu\ntgA5BmTm+j6MOleaTrWXsjSlKlJ6/5nxVPLm1/xI0mxTyQI7BMHRsZRtqSt1\nQ1+tLKPicnJV0nXiKLGY49guXUStzJyY9lOzaLQw8IC2WrVf6wODUgu58m+l\nDsklajeC9u7Kg9xH635SKUmlrww/z2gGhGsJssUMTeiVHxFfu8sYgSPA4+TU\niXS4Z5v6lrTgCwFPNNYnfw3885pht2rm59qFXfPZnnFIfjSEkD+R/Tw8OZSA\n9U+O31v+o0r3QCysvzh0TRG7F+vUCgQQBszlpK+ywX547S67n6xKUU0sJguD\ndHHqk1+qOlV61vXPPmhzz+Z8uJjQ57dVr5SMmySK4pErHrbk+5/NuGTnfRFV\n/tiQN9+arzhQFtdyykws3HE9WTeXEKC/Wj+xb344uf1ZqsunL+wrzdNbx2O8\nHMFsn7aKhesowjIpHoaNNf+EBMNl2NE5S+SGuiIvWUtnqAg5nAYym8zCi6Yf\naF75ZtMnsyH9i+q36K8g6nzVkJ1oaWAUsPFQ7DxKP1RbIbKMFyjFY1nkYzz0\nAjAp\r\n=eqEi\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDTpoUr81DIVb5wSdSLVc34CJghJryowBxCyFNEqlRp0AiEAyD1jnrhbZVYLpalsAiCAF75N7w403IYj87aK3z329Qk="}]},"_npmUser":{"name":"kbajalc","email":"kbajalc@gmail.com"},"directories":{},"maintainers":[{"name":"kbajalc","email":"kbajalc@gmail.com"},{"name":"alitelabs","email":"labs@alite-international.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.2.4_1604491452701_0.16291638038663514"},"_hasShrinkwrap":false},"0.2.5":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.2.5","license":"MIT","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag beta"},"voyagerVersion":"latest","dependencies":{"@apollographql/graphql-playground-html":"^1.6.26","@creditkarma/thrift-server-core":"^0.16.1","apollo-server-core":"^2.9.13","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.42","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.6","graphql-type-json":"^0.3.2","jsonwebtoken":"^8.5.1","ms":"^2.1.2","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.4.0","wtfnode":"^0.8.3"},"peerDependencies":{"typeorm":"^0.2.21","graphql":"^14.5.8"},"clientDependencies":{"graphql-voyager":"^1.0.0-rc.28"},"serverDependencies":{"aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","body-parser":"^1.19.0","express":"^4.17.1"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.7.6","@types/aws-lambda":"^8.10.64","@types/aws-serverless-express":"^3.3.3","@types/body-parser":"^1.19.0","@types/express":"^4.17.8","@types/graphql":"^14.5.0","@types/graphql-iso-date":"^3.3.3","@types/graphql-type-json":"^0.3.2","@types/jsonwebtoken":"^8.5.0","@types/koa":"^2.11.6","@types/koa-router":"^7.4.1","@types/ms":"^0.7.31","@types/node":"^12.19.3","@types/uuid":"^8.3.0","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.19.0","aws-sdk":"^2.784.0","aws-serverless-express":"^3.3.8","body-parser":"^1.19.0","express":"^4.17.1","graphql":"^14.5.8","koa":"^2.13.0","koa-router":"^10.0.0","raw-body":"^2.4.1","ts-lint":"^4.5.1","ts-node":"^9.0.0","tslint":"^6.1.3","tslint-config-airbnb":"^5.11.2","typeorm":"^0.2.29","typescript":"^4.0.5"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.2.5","_nodeVersion":"12.21.0","_npmVersion":"6.14.11","dist":{"integrity":"sha512-PxteZ28aZOntTrc6gaY3xT56lZz6wgnMdrK+JUgWhgyV/enbkg4pUxlRIDQvYsky4T9phNalqKuoSYXsGgK82g==","shasum":"adfa525ac16ba0b07a3b7df43f551ab90a90ad5f","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.2.5.tgz","fileCount":304,"unpackedSize":1030708,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIH6aEv4ti1xv2iJXJ/5uc/uBB7YZ+svGC9DlCCvNYcbJAiEA/TLuAnr4cEkKMieVKVCFMbWWzo318LI82Xs4aUBLvCc="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiVqAhACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmqk8w//Q8bLxQ1s6ZvBh8Vj+J6611c9RbXKpZRvsFWQJ4oMubxzTSV5\r\ncSbHAojCH0AAIw+DPXNWvjnrBZ3xJP0wmJCDmM6Nq6P82lTX6XfdIAzD3A8E\r\naxlgUj2q3NIx2l06RhsGZevXg0WDFe649TGA5y3elrd0uGq4fahPOK1NQbu8\r\nstMSFgfgXYF3DcdxylW01Ztbgjxj4LDiD6rl7KIbE4gO/gOA2PKjoYYh5cLQ\r\n9ucW5pPwHPfch+nBMkW0xY4e5huBlVFt94WuGNv3bRbek0Ch8e790x4UYGht\r\nKpzAaml3OcwRiNMd0Q93vJ2Oh4p+zRsZ4FGgAMZrv1cwkq9QutSutlIknOyg\r\nypZMaMBzsRfnkvN2KS/6yyOStghKGlgeurklPNRz0aPGiumWVs7hfD/2YQRf\r\nsWW5lYQf2Y4D/NX4LBCbEr+FZFG5b+fxIDYp206ARobrrcjXH52j35skJnO8\r\nCiToAbuB5rGNMZLGQYyX1E7Vzw/2MQsmBriPQSp7OETUyDsQ9LbZo3Bm2Zze\r\nNU9Isy4O/03EqbpXIhmuofBLtuCTbW2dBNce+zWwA4wCv+T+hGjCfqFdbuT7\r\n9KtW1wmTSae9LSMg8CMDw/afUtRmGbW9NPw8BhJgyx5Jx7uDawB+mqUyE/EG\r\nSpV7bkytV5hEAyZhu3F1r5mEfkeAOrky4JU=\r\n=fCZb\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"directories":{},"maintainers":[{"name":"alitelabs","email":"labs@alite-international.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.2.5_1649844257005_0.026775208386814908"},"_hasShrinkwrap":false},"0.2.8":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.2.8","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag 0.2.6"},"voyagerVersion":"latest","dependencies":{"@apollographql/graphql-playground-html":"^1.6.24","@creditkarma/thrift-server-core":"^0.15.3","apollo-server-core":"^2.9.13","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.38","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.6","graphql-type-json":"^0.3.1","jsonwebtoken":"^8.5.1","ms":"^2.1.2","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.3","wtfnode":"^0.8.0"},"peerDependencies":{"typeorm":"^0.2.21","graphql":"^14.5.8"},"clientDependencies":{"graphql-voyager":"^1.0.0-rc.28"},"serverDependencies":{"aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","body-parser":"^1.19.0","express":"^4.17.1"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.7.6","@types/aws-lambda":"^8.10.36","@types/aws-serverless-express":"^3.3.2","@types/body-parser":"^1.17.1","@types/express":"^4.17.2","@types/graphql":"^14.5.0","@types/graphql-iso-date":"^3.3.3","@types/graphql-type-json":"^0.3.2","@types/jsonwebtoken":"^8.3.5","@types/koa":"^2.11.0","@types/koa-router":"^7.0.42","@types/ms":"^0.7.31","@types/node":"^12.12.14","@types/uuid":"^3.4.6","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.9.13","aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","body-parser":"^1.19.0","express":"^4.17.1","graphql":"^14.5.8","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","ts-node":"^8.5.4","tslint":"^5.20.1","tslint-config-airbnb":"^5.11.2","typeorm":"^0.2.21","typescript":"^3.9.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.2.8","_nodeVersion":"12.21.0","_npmVersion":"6.14.11","dist":{"integrity":"sha512-WuFMGEGEGR/ghZK++TBK2UP4q8SeXE6vmrAdQLcTIJZK7LeVGFYoemaWXXRWa2IatfF8qbPOX5IauYw6iT3dnA==","shasum":"d49f2815aef281056ace959bcd712946379bd703","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.2.8.tgz","fileCount":303,"unpackedSize":1048869,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCp9DCpW8ftBPKPHw/S00CRYbCO8byvHsxJSYCGprjDhAIgart17kPNrEWkblNGD62mIYghKcUbkzmydnMaVtJA2fE="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJimcgJACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmq/exAAjGgINsxLZ/ycpMIdCeXOECEpQEjJFxqPt19KWRGwCFGhzJ6I\r\nVE9ccb3CN0NAWiMvMNg3P40HNEBdZfkSaGPo+bwwP8abvGGuKM2k3hyVaUVg\r\nQ9Fai7gdBKQ1u99g1XrrslnmgVU6v8VeibtiTAvLEqxGfOpEnDnrn726Cfc3\r\nBHDTRlcAguIZurfRhzeB3H32T/AXSoE/Nb2+FWlpdgxQ4ND4fMUEpdVzms3k\r\n3zNyODe2oQYtJVX7hw/VctMt4dNCTCLxroH84+3/Z7UdObZLsMPycTdKk4Dr\r\n8UeX6ai8PDQoow1FgH4VN3pRwlHJ1iPIO6ARYshv86igwDFavcPVKsUxJ3SU\r\nPajkn2/GuM+D0w1ezLZ8CERm/cm+Fqp3aA9EiyGoB1zwySL44HuumyTkmh43\r\noK/pJYUpMwgdxD1BgrDdLTk7tNu63knq9hjYCiuEUR0KfeKgWHliW4dI/Apb\r\n8rOym9rL8xrV6OyEzZLNO/DzGaXjEeoasYUvoPwoW4aYSxmCuqc14B3JDJPy\r\nB0hEQtLNti8o+hb6Ll44CzAJKk0BS2vyoknKrzbHp1Z9qgtgTjBoEQJpH66O\r\nP4lmgk5c00VpB88TU6trtSR9FM12XBJJplqiCBPy5CchOUEMVXnS0ljPRGX3\r\nJdLgpsskPqMHTCZE1taH/JO7OWE0Utetw40=\r\n=laaV\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"directories":{},"maintainers":[{"name":"alitelabs","email":"labs@alite-international.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.2.8_1654245385495_0.6266428066455385"},"_hasShrinkwrap":false},"0.2.9":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.2.9","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag 0.2.6"},"voyagerVersion":"latest","dependencies":{"@apollographql/graphql-playground-html":"^1.6.24","@creditkarma/thrift-server-core":"^0.15.3","apollo-server-core":"^2.9.13","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.38","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.6","graphql-type-json":"^0.3.1","jsonwebtoken":"^8.5.1","ms":"^2.1.2","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.3","wtfnode":"^0.8.0"},"peerDependencies":{"typeorm":"^0.2.21","graphql":"^14.5.8"},"clientDependencies":{"graphql-voyager":"^1.0.0-rc.28"},"serverDependencies":{"aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","body-parser":"^1.19.0","express":"^4.17.1"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.7.6","@types/aws-lambda":"^8.10.36","@types/aws-serverless-express":"^3.3.2","@types/body-parser":"^1.17.1","@types/express":"^4.17.2","@types/graphql":"^14.5.0","@types/graphql-iso-date":"^3.3.3","@types/graphql-type-json":"^0.3.2","@types/jsonwebtoken":"^8.3.5","@types/koa":"^2.11.0","@types/koa-router":"^7.0.42","@types/ms":"^0.7.31","@types/node":"^12.12.14","@types/uuid":"^3.4.6","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.9.13","aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","body-parser":"^1.19.0","express":"^4.17.1","graphql":"^14.5.8","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","ts-node":"^8.5.4","tslint":"^5.20.1","tslint-config-airbnb":"^5.11.2","typeorm":"^0.2.21","typescript":"^3.9.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.2.9","_nodeVersion":"16.17.0","_npmVersion":"8.15.0","dist":{"integrity":"sha512-iYbE9j7VfTchvQHocy3hnAJBAiI9K+XAA+K8C9CuOpmmBFstwxYJSAwvfDh4GC/e8JrT7UxkcsbkaVQXi106tg==","shasum":"8281247e07ddcf77f81da8adda6020471a20177a","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.2.9.tgz","fileCount":303,"unpackedSize":1049116,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGKa+Ychs5nosPJ1i4EGpcf0FX6nNdknSBX8E6UX/BI3AiBAcSQofvqb3yGCgeCdDS25c1XJVbJfuNPsf232tuwHLw=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjFagvACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpJMw/9EwS+EFyEo7OvB+x1MfmqWwby7pACk9A8QK82JhFi0zjohqBt\r\nguus0kSFsdPn4dWPU1YsCXQKLkLKuAkcLZk+pGrS0mXOngx1zgCkeXl0xZVg\r\nL1NBdjtRz/2JgdwaRJdNDJKpPuf5QhJ2vOZX8jwKfKADIT2fiwX+x0T1Ng98\r\nzxbIWRrnmy8SE51bFeajOyppI8dz7IcSWCgcasCRs0p+2jj3ukilU9GkMBc3\r\nBeL/+fRIVlW0lPM9rceL0x/4HFRLW7ttsX2WwyVeakafzSZ26yvEpKrQfNK2\r\n/KORZ9AAOhh81pDPOhWvCSB439w90GqgLzE1LXybDIoC5OSYu0F6vXG4YOrA\r\nxeBGhWY6KFwCJQ8JF1RFBrklnUtGFtW/1stWIy8vs6i8SVGKTTuBYw1DhHdD\r\nCcMMP1yzz3LM+4Msu8U0GyAynTNKPj5M/q7mC1P4d6EDi8pCtQ9iKspRTEdq\r\nsUuU/T63xGRpR7kgFbcnHQS/+5F+zlMSQXh2jzJ6AHMfgZ29MveomRfNfZ9q\r\nGCpaad3de1E6NNsmUXRx0eOMlRKcGt0JqaH2BOBznPILGAOvx+g2zeceYR7d\r\np+aQHlvaYhb+Ycl3VnUSJVL+6VbTq4hhLoIPoC/QTtTcNSgwUN3HE3uay/qi\r\nFuMWQmittoy2YxcqRpTL8ZBX3APqvZqOAIc=\r\n=C8gW\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"directories":{},"maintainers":[{"name":"alitelabs","email":"labs@alite-international.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.2.9_1662363695618_0.5506478028060666"},"_hasShrinkwrap":false},"0.3.0":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.3.0","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag 0.2.6"},"voyagerVersion":"latest","dependencies":{"@apollographql/graphql-playground-html":"^1.6.24","@creditkarma/thrift-server-core":"^0.15.3","apollo-server-core":"^2.9.13","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.38","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.6","graphql-type-json":"^0.3.1","jsonwebtoken":"^8.5.1","ms":"^2.1.2","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.3","wtfnode":"^0.8.0"},"peerDependencies":{"typeorm":"^0.2.21","graphql":"^14.5.8"},"clientDependencies":{"graphql-voyager":"^1.0.0-rc.28"},"serverDependencies":{"aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","body-parser":"^1.19.0","express":"^4.17.1"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.7.6","@types/aws-lambda":"^8.10.36","@types/aws-serverless-express":"^3.3.2","@types/body-parser":"^1.17.1","@types/express":"^4.17.2","@types/graphql":"^14.5.0","@types/graphql-iso-date":"^3.3.3","@types/graphql-type-json":"^0.3.2","@types/jsonwebtoken":"^8.3.5","@types/koa":"^2.11.0","@types/koa-router":"^7.0.42","@types/ms":"^0.7.31","@types/node":"^12.12.14","@types/uuid":"^3.4.6","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.9.13","aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","body-parser":"^1.19.0","express":"^4.17.1","graphql":"^14.5.8","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","ts-node":"^8.5.4","tslint":"^5.20.1","tslint-config-airbnb":"^5.11.2","typeorm":"^0.2.21","typescript":"^3.9.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","gitHead":"f2c3355a0af6b9a996ea80cc32c38567499143c6","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.3.0","_nodeVersion":"16.17.0","_npmVersion":"8.15.0","dist":{"integrity":"sha512-6N5ukurfTfdrskXo4HhGP/so9RE0E4h5D3neR2Iy3DTvnCsh0go2JUBQIZ7D5jIOUuUubEtE2gbZuv2AK4Ef9Q==","shasum":"37d2ae3a0353a8a4e76187df318143ef6cf3a64f","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.3.0.tgz","fileCount":3,"unpackedSize":97911,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHWXUzONP72CSa6H4xXmk0MA91A2VGZv8gtvx5sNoIWdAiBvJazmOM4kmSSH+eMwJtn420fQmeum2XrQPI36KHRu1g=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjPsTnACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrL2w/9HIS2BZws7R2r3Wu1nKFHjMb8W9bxko9HrRnGC8g4YYFU0Rcj\r\nzD1klje94jQWJWzCaLWq753dcBbxEfeOVKYPg7zV0PIUxmd06IJnVJDU0yYE\r\nyoZTjdbC37gdh5N4Y1xoWl/3L3bcjrr+bKnkSKFgiikXM4VSnLE9RKJgHEXU\r\n4rXkPTga8joq+ImPi3bhitEtGI3NctgFcSuz99pGmJmEnXbsg+5gwAGH2zoz\r\nxp5+44dTfRz/uVLJb6vQ5PcRIPw/rRF5rKsgku5JqYVS8Tp9DMot4P3LoAWE\r\n7Bb0lstdxLEKH3yJO5NC/X6U8/n6/EYQEsGOYhSory8lglR2SkgdtgQcKQfX\r\ng7JEayrSYeepmB+2xKGl3eufulZaD7F6kODyUi25//b0UIGopEvq3txQqgIT\r\npVYOS2cqFw8U3r2sHaQM1U0NMMKyH+MFgi6Rtk7Bq/l2UWKKlRkcCV+EXMrp\r\nDtZ8xMv1pejF+fsvoRei4n6cfaAZ0OYJamH3RkKsIzD3NMU/qvN+hw/2Mn0S\r\nzgPlH2OnlRva5Yq6u43EAMXRi4yJ6zucbDNa8zwpYet2J6baBSobzTFwkfIM\r\nIu9ja2LIiEXlKDMLJ2Dq8NkZZ0zKH9haMCToCPW33cv3Ft6M6tQ9WQnrVvXt\r\n+Fej/nd0JdufDiJ8IlWA3RidmXaPk1PVHts=\r\n=F9Mz\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"directories":{},"maintainers":[{"name":"alitelabs","email":"labs@alite-international.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.3.0_1665058023552_0.3554959681788845"},"_hasShrinkwrap":false},"0.3.1":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.3.1","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag 0.2.6"},"voyagerVersion":"latest","dependencies":{"@apollographql/graphql-playground-html":"^1.6.24","@creditkarma/thrift-server-core":"^0.15.3","apollo-server-core":"^2.9.13","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.38","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.6","graphql-type-json":"^0.3.1","jsonwebtoken":"^8.5.1","ms":"^2.1.2","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.3","wtfnode":"^0.8.0"},"peerDependencies":{"typeorm":"^0.2.21","graphql":"^14.5.8"},"clientDependencies":{"graphql-voyager":"^1.0.0-rc.28"},"serverDependencies":{"aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","body-parser":"^1.19.0","express":"^4.17.1"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.7.6","@types/aws-lambda":"^8.10.36","@types/aws-serverless-express":"^3.3.2","@types/body-parser":"^1.17.1","@types/express":"^4.17.2","@types/graphql":"^14.5.0","@types/graphql-iso-date":"^3.3.3","@types/graphql-type-json":"^0.3.2","@types/jsonwebtoken":"^8.3.5","@types/koa":"^2.11.0","@types/koa-router":"^7.0.42","@types/ms":"^0.7.31","@types/node":"^12.12.14","@types/uuid":"^3.4.6","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.9.13","aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","body-parser":"^1.19.0","express":"^4.17.1","graphql":"^14.5.8","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","ts-node":"^8.5.4","tslint":"^5.20.1","tslint-config-airbnb":"^5.11.2","typeorm":"^0.2.21","typescript":"^3.9.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","gitHead":"f2c3355a0af6b9a996ea80cc32c38567499143c6","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.3.1","_nodeVersion":"16.17.0","_npmVersion":"8.15.0","dist":{"integrity":"sha512-7A3hjvUO3LzVNP6CBXz8is3daCnuJowpJNkIOM3SCkWDlWb0dfybOK2IlDK4cCoUXT8j+L/cjgZ+KwHqfOQWOA==","shasum":"53b57614bead052ab62acab93acc7f3ab796b951","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.3.1.tgz","fileCount":303,"unpackedSize":1051310,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDNvLgBuc7+K3nUaT+1S6lbGntm79rt3aDEpa286UtX8gIhAOl5tW8vizMCzW9LfHdjQ9/j4LDADNdY00s4cy337u9+"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjPsmQACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoAOA/+JIO9RitEu61h06ob81gvgi256js3CkyNxk33Wn++2hBMKhcC\r\nUzpKh/dTLMMxpSKy4DafGdElxioDe/F8OxaytP0gejbywSNn3h38O0ZbDGal\r\n1HV227V+49595WpywQ6DrchO7/lK92C9X1geWZP46wjk4QQWHp8vJYhp73JP\r\nu5L6hWzJ64bRkhtzc198RB0S1u9UEx+X53EPQ3w9YUirTWb5y9QEmaatFzN9\r\nUA3aVaLDjppfT42watUF8qc/Jp0InEclyQI5G68aJab4ZmUJTlKExU5ZrL21\r\nt7wODLvYO6eCSB+vWHxlBf7Xf/nigr96Cn1LK1gja3EYjsZe9o8cnM0136r9\r\n2ETZj1sKfC0hXHb0b/RPqCyZcmG48enbLYP2Pyd5K39uf5OpZ8FEt4nF8+66\r\niWsDt/yaOl/ey3/+hLQELicRlQMqwZeqkjlmhNcnuhGjCb8eF/pRwqnfRuYq\r\nXDHBtoetdypSIhnhMMu0q8oGQtmfuT7MBnDjU/K7+rMR6Th2ySOQXvBXyim0\r\na0AVIWKGJQTK8JRXh/myKdOgN++VbasPiNBEXesyFXIUFshLtOkWT7B7k1kZ\r\n470Aqluuzsa11EHks/fOisCiyv86IYmlWWY34DkSYEx231lnQ6KlYWCgTy+M\r\nz8R7wKRV39hKWaxY38wIEWs+bAReMwgknoc=\r\n=MfKF\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"directories":{},"maintainers":[{"name":"alitelabs","email":"labs@alite-international.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.3.1_1665059216027_0.2653862554198114"},"_hasShrinkwrap":false},"0.3.1-dev1":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.3.1-dev1","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag 0.2.6"},"voyagerVersion":"latest","dependencies":{"@apollographql/graphql-playground-html":"^1.6.24","@creditkarma/thrift-server-core":"^0.15.3","apollo-server-core":"^2.9.13","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.38","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.6","graphql-type-json":"^0.3.1","jsonwebtoken":"^8.5.1","ms":"^2.1.2","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.3","wtfnode":"^0.8.0"},"peerDependencies":{"typeorm":"^0.2.21","graphql":"^14.5.8"},"clientDependencies":{"graphql-voyager":"^1.0.0-rc.28"},"serverDependencies":{"aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","body-parser":"^1.19.0","express":"^4.17.1"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.7.6","@types/aws-lambda":"^8.10.36","@types/aws-serverless-express":"^3.3.2","@types/body-parser":"^1.17.1","@types/express":"^4.17.2","@types/graphql":"^14.5.0","@types/graphql-iso-date":"^3.3.3","@types/graphql-type-json":"^0.3.2","@types/jsonwebtoken":"^8.3.5","@types/koa":"^2.11.0","@types/koa-router":"^7.0.42","@types/ms":"^0.7.31","@types/node":"^12.12.14","@types/uuid":"^3.4.6","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.9.13","aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","body-parser":"^1.19.0","express":"^4.17.1","graphql":"^14.5.8","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","ts-node":"^8.5.4","tslint":"^5.20.1","tslint-config-airbnb":"^5.11.2","typeorm":"^0.2.21","typescript":"^3.9.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","gitHead":"5777dc5546626803b1961b80f7f42af20905acdd","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.3.1-dev1","_nodeVersion":"16.17.0","_npmVersion":"8.15.0","dist":{"integrity":"sha512-hThYFXewPyENxzU/+emTMgExunHDnNVKBQ45pFmqndElKZ7SI2toSEnvuntLIC+q3opwdgFmB3NCC34HsgVtjA==","shasum":"fa82a1d7b31d00c465ba6ff22a11de38860e2f1c","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.3.1-dev1.tgz","fileCount":303,"unpackedSize":1051927,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHS5MJImwlN9zqkyVbrAvxAsnlMDogGFh10kAQm6T55/AiApiq441flTGyb7g+GQFx64UOzU8HyHO9vwv4bjfLkiYg=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjPvZRACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmppIQ//U+YcdrQ8h6UK0FWccZldW7EA+G6WCDSH9FiEpE/OmF0wxpT4\r\n7UkJ/t0wa7bZZwC3mE01rg9pML9X3fFNRe/oVlytvDCtEukfiZmDzeLihtMP\r\nFkdqpBwjiJ48zUklrV37nZo+Ter8noJ+rfI8G0C9V1mqauyO0yVzq7Shiq2z\r\nOr5Qy7AD+wOBAoj0BE00Z2jkM6reR0ucjs0Awxw7sp+F2REmlvpgYd8gR3na\r\nRSsuM4BKJK60vgoJ0OoEmR9T4terpGnzxDXMnpzEcwnUoTvZWq3W8plzV/56\r\nxvA0mYUAEoPKBN7rId39PFUhkBMCewZSjZXFOhNcFUtwCKsmkI/Yq5nP9PlR\r\nUouHTSNwLT271r2Lit4YpuYF36D72MsBYdeRc1Pt2loHvXrFUH1TEfWyCYRY\r\ngJtyrFTqiAgMR3ScwYrD0apSKZbblLwHKcvPpOpRYcim44F8Ay0R93L5kSvL\r\nLrPqdcwbmU2wV4RBaQVh2H9fhNElvrsnqvbwkBg3B5NycRUIH6lOsmYCnPcL\r\nhfPab3/3lYBGg3Qd11sPU7mwa97VcAwSDG3VP1F7lNpX0oMcqL7b84tfFMpX\r\nC06Pub5ohutHRw0gCHcjJsjxwuXSGT2Co+U/oLEqovGD5L5mU2dcHru1Kf3D\r\nwH9hzFQHXIIKW2Uc5Q5HE1r748jaonV61CE=\r\n=e+IQ\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"directories":{},"maintainers":[{"name":"alitelabs","email":"labs@alite-international.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.3.1-dev1_1665070673347_0.5253236904890919"},"_hasShrinkwrap":false},"0.3.3":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.3.3","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag 0.2.6"},"voyagerVersion":"latest","dependencies":{"@apollographql/graphql-playground-html":"^1.6.24","@creditkarma/thrift-server-core":"^0.15.3","apollo-server-core":"^2.9.13","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.38","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.6","graphql-type-json":"^0.3.1","jsonwebtoken":"^8.5.1","ms":"^2.1.2","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.3","wtfnode":"^0.8.0"},"peerDependencies":{"typeorm":"^0.2.21","graphql":"^14.5.8"},"clientDependencies":{"graphql-voyager":"^1.0.0-rc.28"},"serverDependencies":{"aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","body-parser":"^1.19.0","express":"^4.17.1"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.7.6","@types/aws-lambda":"^8.10.36","@types/aws-serverless-express":"^3.3.2","@types/body-parser":"^1.17.1","@types/express":"^4.17.2","@types/graphql":"^14.5.0","@types/graphql-iso-date":"^3.3.3","@types/graphql-type-json":"^0.3.2","@types/jsonwebtoken":"^8.3.5","@types/koa":"^2.11.0","@types/koa-router":"^7.0.42","@types/ms":"^0.7.31","@types/node":"^12.12.14","@types/uuid":"^3.4.6","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.9.13","aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","body-parser":"^1.19.0","express":"^4.17.1","graphql":"^14.5.8","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","ts-node":"^8.5.4","tslint":"^5.20.1","tslint-config-airbnb":"^5.11.2","typeorm":"^0.2.21","typescript":"^3.9.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","gitHead":"5777dc5546626803b1961b80f7f42af20905acdd","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.3.3","_nodeVersion":"16.17.0","_npmVersion":"8.15.0","dist":{"integrity":"sha512-K7vZVlCIX/vvSSYhuVPgnz1JnSz/y/aa3E/QZctsVcb7eVt/d6/wddWqfjc4RvrZPd9r/p/v9m+ygB6T4x0ddw==","shasum":"5f48634f69325708ac82822046ee948cf5ed9084","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.3.3.tgz","fileCount":303,"unpackedSize":1051972,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFM0T0D0SHKmP6dpEHOp1KLFWoH5Rof35TukxjdFOEiqAiEAnecoGlxIBQdT5RCCq5dBn38GKBdtgavrgSocDJdBRqc="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjPv1vACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoViBAAleTonmuU6wIw/pGhrxNV4A9O42DchCbt0+HFtDygEHSd0ab2\r\nF7hMZ/XYN58oAKe08zUQ4f14htDkdOxW+yvncsnCMZntQyr6+Ej0v58vjkbv\r\nuRHYKygESSXtfcQw2JXvZ6MOUf6HbuG9z4oua5yafLHwxw6rJkeqtH+p7C1p\r\n13yfOmxmgjsU+0xvnK5DA8rWP3X1l1CPZW1pFG8F9AJwQpuuyHVuAlbSyVvX\r\n53dKZF3G2DHegTVof8rGtC1sjCBX6aBJZnBLa8cRgNIhksG/l0O1rfpkQIwQ\r\ndp8NOUnuH77tAO+nnQYnyp94R8Znbd1Y9S6C9b/q80MVLx9UZHa7geJ858R+\r\ndfnt4+eHCErQ0N/q+sBa6Vg3U7TLzlnzxIMn6p4iSMLeB1HPMaGwgRsaoPpd\r\nTX3o19zw111GKNZ46ejOAjUObdWNt46DHOD9lw1di05Byu9M1R88vS5lqD/x\r\n538z3QQTyfj42bxluWpsZhM4J2u7yOvyEkFnEMWmzzyoOIYiTANEKVnCLR/n\r\n9u+ZDGI7TkUAf8u7/TNEhHQrGkItV80SWdxUfdmYSrsapzluse9d7VXw41J+\r\nZBb96UYt/5isrNpcL/1cvppAasgaXxAL3HNs5qUtkcenZYRQuwgXj1m0BepH\r\nEqO5JqufQtG1WnSwWQ2w0K+sZHANDF6ToDk=\r\n=CMih\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"directories":{},"maintainers":[{"name":"alitelabs","email":"labs@alite-international.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.3.3_1665072495558_0.021241120579400974"},"_hasShrinkwrap":false},"0.3.4":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.3.4","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag 0.2.6"},"voyagerVersion":"latest","dependencies":{"@apollographql/graphql-playground-html":"^1.6.24","@creditkarma/thrift-server-core":"^0.15.3","apollo-server-core":"^2.9.13","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.38","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.6","graphql-type-json":"^0.3.1","jsonwebtoken":"^8.5.1","ms":"^2.1.2","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.3","wtfnode":"^0.8.0"},"peerDependencies":{"typeorm":"^0.2.21","graphql":"^14.5.8"},"clientDependencies":{"graphql-voyager":"^1.0.0-rc.28"},"serverDependencies":{"aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","body-parser":"^1.19.0","express":"^4.17.1"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.7.6","@types/aws-lambda":"^8.10.36","@types/aws-serverless-express":"^3.3.2","@types/body-parser":"^1.17.1","@types/express":"^4.17.2","@types/graphql":"^14.5.0","@types/graphql-iso-date":"^3.3.3","@types/graphql-type-json":"^0.3.2","@types/jsonwebtoken":"^8.3.5","@types/koa":"^2.11.0","@types/koa-router":"^7.0.42","@types/ms":"^0.7.31","@types/node":"^12.12.14","@types/uuid":"^3.4.6","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.9.13","aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","body-parser":"^1.19.0","express":"^4.17.1","graphql":"^14.5.8","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","ts-node":"^8.5.4","tslint":"^5.20.1","tslint-config-airbnb":"^5.11.2","typeorm":"^0.2.21","typescript":"^3.9.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","gitHead":"59fadf2d6b875c92c7ac566b5c9c24a2f846c68d","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.3.4","_nodeVersion":"16.17.0","_npmVersion":"8.15.0","dist":{"integrity":"sha512-MCrqkpZuqdfnZGSNCbGpibFzRiyR+4UJrd5jDfSPeaeQhvgbtan+tVCmy0CwxsOTmPNt2nGAeBrnyNlmAWTGQw==","shasum":"751a1c7250075d32792deded611e7791d58d8396","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.3.4.tgz","fileCount":303,"unpackedSize":1052002,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDqJghKtFe1MBu9ZLHkVURACV3SuD/Z6eB/Tfbygyl5fAIgXeiFe3eLyKp022dChjGr8nc4HjQpCfqOkQ5onnjNACk="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjPwYYACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmpc9A//dxikarVgp7lmTFl6/JyKkgoYtPQtxkl/ce/pdhqpfii3aE8B\r\nWiRqYGio609hkqzArEporF41uYOqvRyJH90TbVKDzG8sItNlOmHZSJob9E2z\r\ncGl7Q2KExmTGr2Ncs1oead44mmmSOI3zjqIpy4WOrFe1YWRMUCG+bXq0E5aC\r\nHJ+8uEP341SIP3K9ODytn2LfH2SMLT6P1qzYF8LB0Q5C0EeTjKQrk1MZ/BLO\r\n1bgQgB67gRcnxKyvvxJP7gshdN3w8+6jE9d75iQ7Ur2mb13e9IGyuKBYiZEa\r\nSxHLvU73C7SMX92YDYBWVMwodklbDnYo+TglaXb6K5OtPWZIyHDR5P3dRgjC\r\nzaZh3JoDe/E8rJ/UUTuB9U45sHFch7Qa1BK4UrJ73l+ltFop5aQlZlvkEWuu\r\n3kwNwSWC1ugyrhmMJks41dAnz5+k2xiRVi29oV3hZh6TlHQ/W26bP8t82Ss0\r\nTk4kCN4zfVV1jSFZvXcuvWKKfetWyxkuVBy5l9UXNEjTGk9ZeQF/4rVIsk1l\r\ndkOX2tdCOFZC1iNzxGgBjBhFIu2LcyYRcArvc7llVZnFvKuTMuXTdjPny/tV\r\nQ8xAFHTWc98kxnaXfJcTNrMhb1Blj1eAvlw02VT/sgevBqXMlcBUuxupV2X1\r\n/vVPWEzBDdQaEbcCLhO0a4R8OwJ9K9MAi1M=\r\n=yrek\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"directories":{},"maintainers":[{"name":"alitelabs","email":"labs@alite-international.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.3.4_1665074711876_0.048926505287345545"},"_hasShrinkwrap":false},"0.3.5":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.3.5","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag 0.2.6"},"voyagerVersion":"latest","dependencies":{"@apollographql/graphql-playground-html":"^1.6.24","@creditkarma/thrift-server-core":"^0.15.3","apollo-server-core":"^2.9.13","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.38","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.6","graphql-type-json":"^0.3.1","jsonwebtoken":"^8.5.1","ms":"^2.1.2","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.3","wtfnode":"^0.8.0"},"peerDependencies":{"typeorm":"^0.2.21","graphql":"^14.5.8"},"clientDependencies":{"graphql-voyager":"^1.0.0-rc.28"},"serverDependencies":{"aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","body-parser":"^1.19.0","express":"^4.17.1"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.7.6","@types/aws-lambda":"^8.10.36","@types/aws-serverless-express":"^3.3.2","@types/body-parser":"^1.17.1","@types/express":"^4.17.2","@types/graphql":"^14.5.0","@types/graphql-iso-date":"^3.3.3","@types/graphql-type-json":"^0.3.2","@types/jsonwebtoken":"^8.3.5","@types/koa":"^2.11.0","@types/koa-router":"^7.0.42","@types/ms":"^0.7.31","@types/node":"^12.12.14","@types/uuid":"^3.4.6","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.9.13","aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","body-parser":"^1.19.0","express":"^4.17.1","graphql":"^14.5.8","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","ts-node":"^8.5.4","tslint":"^5.20.1","tslint-config-airbnb":"^5.11.2","typeorm":"^0.2.21","typescript":"^3.9.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","gitHead":"59fadf2d6b875c92c7ac566b5c9c24a2f846c68d","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.3.5","_nodeVersion":"16.17.0","_npmVersion":"8.15.0","dist":{"integrity":"sha512-yqC6H7GvvJaLZMIaihBCn1D2oLpXRFk0KasQmQIWMskICEu1yMcblKAGXbm83xL0/83/rKcab6w4SxtbNi8Kaw==","shasum":"13f8d273259981efac171386ded9f66996e5565b","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.3.5.tgz","fileCount":303,"unpackedSize":1052113,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCtIZJ1790eH7loHFBZGlRazwW7jYY8TDoZDA5eteST4QIgOYReBY/fiUzWPAXqJFX9LNtBovDcM7sAFhOAzAeF/6c="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjQ9OVACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqMug/9EyY/Zu/l9bvHumoP2V1cPi2Czv6DraOCXUeRXfPZ9igisT+c\r\nUUc0SkfJiWHW7M6dNKt4ljEGjtoabAxW9TLWfPDTG2a1P7vGkjPccv6Aq9mU\r\n8kjjSyXzoZHIs0ziL6HES6VHO0XIVdiknMNb4iC9jGZbmk9gbm1sT6hbJiMq\r\nNJwfvq0UU0GVH1UyypO2P+MgJnwmTfXRfx3GdI3BhiWZD8RxIIo4A59QHy0q\r\nhD4VrJqxCqlvtDOt4uvWtMT2jGTfU0EnMlOJFlE2CFy3lCyX38ThGLRpRsAi\r\nMQ2OvjHikDRXyY8zqa8RM/BGnH2pYhJfr8YRfETszMVqEk8YtjCs+vU+sUQl\r\nE3aqDINooJypDS2VwV8dJ41uYg0IsuaF2stwfcvNBHQf143sTeQIbipMoRH8\r\nnq2utYkPnahcS3x67jQsPlvjbl3PgI6m5POOskRO3Zjdb526iQmEHKkPC6/t\r\nFz4CX+efMHTX6x84N9UNYDhU+ixaUHDWkaYYmS3MkTBxBwWaCbDtYjTMhJCD\r\nNMbCKVvJ0iJtgK0H4ryMOvperdsN1myvHlVt9I6SZ5/u4KycB95AvWd3kkZa\r\nk72aISJfjZOz53q4fuAO4KtOFbCdP8X+ijYKPJlLHIZE4cYZwBEq5ZWsrBFU\r\nB6A9dGZSDIN/Zloxx8G1Cp66MMVUYb7kSTg=\r\n=aMSl\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"directories":{},"maintainers":[{"name":"alitelabs","email":"labs@alite-international.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.3.5_1665389461621_0.7333258446341184"},"_hasShrinkwrap":false},"0.3.6":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.3.6","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag 0.2.6"},"voyagerVersion":"latest","dependencies":{"@apollographql/graphql-playground-html":"^1.6.24","@creditkarma/thrift-server-core":"^0.15.3","apollo-server-core":"^2.9.13","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.38","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.6","graphql-type-json":"^0.3.1","jsonwebtoken":"^8.5.1","ms":"^2.1.2","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.3","wtfnode":"^0.8.0"},"peerDependencies":{"typeorm":"^0.2.21","graphql":"^14.5.8"},"clientDependencies":{"graphql-voyager":"^1.0.0-rc.28"},"serverDependencies":{"aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","body-parser":"^1.19.0","express":"^4.17.1"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.7.6","@types/aws-lambda":"^8.10.36","@types/aws-serverless-express":"^3.3.2","@types/body-parser":"^1.17.1","@types/express":"^4.17.2","@types/graphql":"^14.5.0","@types/graphql-iso-date":"^3.3.3","@types/graphql-type-json":"^0.3.2","@types/jsonwebtoken":"^8.3.5","@types/koa":"^2.11.0","@types/koa-router":"^7.0.42","@types/ms":"^0.7.31","@types/node":"^12.12.14","@types/uuid":"^3.4.6","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.9.13","aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","body-parser":"^1.19.0","express":"^4.17.1","graphql":"^14.5.8","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","ts-node":"^8.5.4","tslint":"^5.20.1","tslint-config-airbnb":"^5.11.2","typeorm":"^0.2.21","typescript":"^3.9.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","gitHead":"59fadf2d6b875c92c7ac566b5c9c24a2f846c68d","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.3.6","_nodeVersion":"16.17.0","_npmVersion":"8.15.0","dist":{"integrity":"sha512-qCgKTZp0XQgv5wbRGRXqChW/FCKzopw0IteYFmrj1A794L0FS+Sgc3x95QeDzSDzNQt92wMpz3i6++JWysVeTw==","shasum":"f94bbe28946342c5bb2e4b4c48deff049fec2b75","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.3.6.tgz","fileCount":303,"unpackedSize":1052184,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFR2yCQzirDGbvw0mu0p1291Kcd+x2reBKcC4WZQc8XXAiEAjtXlnfoGz+AsrRVWOPLIa8R+/25CWZJaEZ93MM8ZkEo="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjSTCdACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmo36Q/+KDn3sJhVsVHqq2bMs/xrsyfOoLNMo/TzjZPzv0+Hw4ppZg2x\r\nna14RQS5yoAJImatRh9r1P7HVeQBYIXf9WDL/tLG10AO9yabkVzqGY4df5cE\r\ntxwGi1izle5cIp23I9dH9G9dNqdsFDuK66cQWEvE2os/tCTPB4AmRnDIXY2W\r\nR45I3kwf71VcKjjN1Kp8zyJ/J7+q05UzZz3lfeDecSJo24d2VfJEqP2PFEMx\r\n14WhIakgVJDNnbwYDiUBmC5arof7CqHEIPyU3MjJzpB5b24IIwh0ugXyXJ0q\r\nV6z36O5SBTq7sIvOcwEYlE5lf38w6U8eMFov+mX79lO1we6YrgffIiK9E/K2\r\ngqSPxK2jJ6/klgkmwPG92+3i54oNZ7rG5WLWNoB3ALdgLY0LpFYfLw25dayo\r\n6/tsR6foe4tV/8FZdEVWdVCEpF5NIeRrb42mNKcea83rI6u1U3KiKUXkgk+F\r\n2LiqOxszoqggRjkm+umeRNpDbdUULttDotN+5MzX9VyLOlCfCMa1LUYadTj/\r\nzslzuUlVDN8gbca2EMiqjK+t/iOPzIEw2uF6e9RuhWyfKGAkf5QD3Y43SJ6j\r\nqD4XiLkP3kVVQR2r0wFxP4oLxHQw/HH9HSOt/noW6lGkC41S786JFOPPinNG\r\nSaVM6CD2PIi4hYSiznpYA4g3jBz2WfJnB8s=\r\n=wxuc\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"directories":{},"maintainers":[{"name":"alitelabs","email":"labs@alite-international.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.3.6_1665740957316_0.2832673316873737"},"_hasShrinkwrap":false},"0.3.61":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.3.61","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag 0.2.6"},"voyagerVersion":"latest","dependencies":{"@apollographql/graphql-playground-html":"^1.6.24","@creditkarma/thrift-server-core":"^0.15.3","apollo-server-core":"^2.9.13","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.38","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.6","graphql-type-json":"^0.3.1","jsonwebtoken":"^8.5.1","ms":"^2.1.2","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.3","wtfnode":"^0.8.0"},"peerDependencies":{"typeorm":"^0.2.21","graphql":"^14.5.8"},"clientDependencies":{"graphql-voyager":"^1.0.0-rc.28"},"serverDependencies":{"aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","body-parser":"^1.19.0","express":"^4.17.1"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.7.6","@types/aws-lambda":"^8.10.36","@types/aws-serverless-express":"^3.3.2","@types/body-parser":"^1.17.1","@types/express":"^4.17.2","@types/graphql":"^14.5.0","@types/graphql-iso-date":"^3.3.3","@types/graphql-type-json":"^0.3.2","@types/jsonwebtoken":"^8.3.5","@types/koa":"^2.11.0","@types/koa-router":"^7.0.42","@types/ms":"^0.7.31","@types/node":"^12.12.14","@types/uuid":"^3.4.6","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.9.13","aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","body-parser":"^1.19.0","express":"^4.17.1","graphql":"^14.5.8","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","ts-node":"^8.5.4","tslint":"^5.20.1","tslint-config-airbnb":"^5.11.2","typeorm":"^0.2.21","typescript":"^3.9.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","gitHead":"59fadf2d6b875c92c7ac566b5c9c24a2f846c68d","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.3.61","_nodeVersion":"16.17.0","_npmVersion":"8.15.0","dist":{"integrity":"sha512-09lHravU8CdvjQ4qztug2l98vWaTL/m+yS9+FUXetGKmz0XjpY2xb1bSBB8P+0ve7a8CJf8/Dgw6vvielLhbeg==","shasum":"b18ee8c85875fb3aad612b8b5a1bf0233cd22001","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.3.61.tgz","fileCount":303,"unpackedSize":1052478,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEy4kQ+R06moclxKjs+V4cSU+RWPZxeosO6yNsYrGlhbAiEAqSzqRBamJSeSOXc5lh5mP+KwZ6pe8W+M4kba3ENcA/Q="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjW5B8ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoAERAAgkExmQKGdYEn69D2aA9koc639MJy3icrrHgR/f+vwHDfH3Za\r\nlVAL4fk1ADIkUrjZ/DaOz+gbnAlexJHTAwbdMdb6ezqzCWZ1yFBtgDB6tG+N\r\n8mIJfQTTEyq78lOqheJxyjf9Es2td/HqksU1TxVcn5S2HAkzlLMj9FSMEqTf\r\n1tv0f/oVsIgHS8YtlNcvvwxrjCLSUggHXhGUMnR/8tsT4zpKTkSHFmy6FNiv\r\n+p1MDRCzUexgeDVi7Z1SUDNvnPtr3pS5yx/00NCRpPh6XupPOFNORTAzAHgA\r\nDlstAGVAQ8t5BlzHCt/KaFSD9u/wSg7oxx1ctpysx2g7Q81Qa2hcsiuE2c7g\r\nYEmLXBAkS8yoUpCWxjJcJe/jhCBVh8tjNI+qbHd1GGUs2rNVq+io+6j+aM6t\r\n51Xa0W/8+SuyAPqiTqAe2N4V01z1Zswi6T6p/w0lTnLHsKjfBdd1KZ++xThu\r\nZyLlDQICMbr3iDG8vr59P0QmsbKqhGzopzfELrlP/stVW7Q1+jixK2EmulkK\r\ncVzurAH2XsueMImTDTcb43fb8dAWdaAMrGLb/MCPJGqlyLdqERF1+6smJQlp\r\nhepE9hPDsP6Ria7phBYZh7AbTMWtf2bq10V08MwQoKBZ8ZuYZHBhV59ZrVsZ\r\n/MMMiQS7pomxwFoSRgFstjAlAXz3c3tYM7g=\r\n=zsVC\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"directories":{},"maintainers":[{"name":"alitelabs","email":"labs@alite-international.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.3.61_1666945148604_0.3897667328992447"},"_hasShrinkwrap":false},"0.3.62":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.3.62","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag 0.2.6"},"voyagerVersion":"latest","dependencies":{"@apollographql/graphql-playground-html":"^1.6.24","@creditkarma/thrift-server-core":"^0.15.3","apollo-server-core":"^2.9.13","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.38","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.6","graphql-type-json":"^0.3.1","jsonwebtoken":"^8.5.1","ms":"^2.1.2","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.3","wtfnode":"^0.8.0"},"peerDependencies":{"typeorm":"^0.2.21","graphql":"^14.5.8"},"clientDependencies":{"graphql-voyager":"^1.0.0-rc.28"},"serverDependencies":{"aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","body-parser":"^1.19.0","express":"^4.17.1"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.7.6","@types/aws-lambda":"^8.10.36","@types/aws-serverless-express":"^3.3.2","@types/body-parser":"^1.17.1","@types/express":"^4.17.2","@types/graphql":"^14.5.0","@types/graphql-iso-date":"^3.3.3","@types/graphql-type-json":"^0.3.2","@types/jsonwebtoken":"^8.3.5","@types/koa":"^2.11.0","@types/koa-router":"^7.0.42","@types/ms":"^0.7.31","@types/node":"^12.12.14","@types/uuid":"^3.4.6","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.9.13","aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","body-parser":"^1.19.0","express":"^4.17.1","graphql":"^14.5.8","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","ts-node":"^8.5.4","tslint":"^5.20.1","tslint-config-airbnb":"^5.11.2","typeorm":"^0.2.21","typescript":"^3.9.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","gitHead":"0f54762cdf84a2b43e9f294f1af45c417ce52fcb","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.3.62","_nodeVersion":"16.17.0","_npmVersion":"8.15.0","dist":{"integrity":"sha512-LAiVAcKT+uKFKBzOY3LG2Kn1RHfjmM3K4GuJZUqzfFQMKUV2Ae0boMi0NoZg2os0h+2+WmKhg0DWA5eOevzT6w==","shasum":"e075b0f88c2363ac80ebdcd98bd463025224c8a0","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.3.62.tgz","fileCount":303,"unpackedSize":1052478,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQClPIsF5dZiJ2f9LJzOUvUxLSn4/6EQrwy4mKKwWDm86wIhAL0Io0h2g4ewkoAKqQP2zed/Qpev0guRmyQht5jwQi/v"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjmbikACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrIlhAAmaee4ts6sGafkjjpg+0Q9tor7rDQKr5MWzn1dog9cyb+bn/D\r\n+Sh7DrGphU33dWHabZMcpeviUAdARi4sspPE/SH/DaePrOI4r/zKcwSM1vC3\r\nloOSv8uVlkK0/CdzLMC6bUefU35vCINbPxXlVZz7iK82AyzKnmWa5pnTXY9V\r\n64jfM9MGesgN5HHomlzErAaGc1xlXXxOZQIdiciK0CXZ/UJVKxXGhXuHo0Cs\r\nEgpjuVyJ+o5P/Wp90uIoZEa10/jS5PCPbISsat1HETrJrcqsypaX+NmyZnZY\r\nCAxBxLVEdQPVmgyIxRLFPz2NW8O4LkvDUja2oAtWZ1+sabYodGD2tvhLXkXt\r\nDLclHbiyexmXM79Y5zOl0dLL1RJwHAZVCgjMCyiCKNXfjFg8OWD5zCEFJ6DI\r\nui6vlKlxVmDKVzvjuKloFFwazqQY4NqSPmdgC6PmbZpOZPM5Iv5ncGbYxZmC\r\nFWXVawkXSE5lYkWPB8V2OHM2TfDiy6LzxMN8CNw4vvzRObJ1+CQyEErYEgtx\r\nqlVQCaq4KT+7SanprcNikBn9zrdrwIZlV6o04z0mHo4vRDVWH6ktfJtOer6L\r\nV5IwKvungki2uurMthchFc6ABIErDg9Z5qyxpI51Qo4JT+QkAcStWecNkayG\r\nkns43Q2K4kA0S0aD6nfIsBKTklAIOoSgOEI=\r\n=tBTo\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"directories":{},"maintainers":[{"name":"alitelabs","email":"labs@alite-international.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.3.62_1671018660678_0.7669382736972918"},"_hasShrinkwrap":false},"0.3.63":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.3.63","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag 0.2.6"},"voyagerVersion":"latest","dependencies":{"@apollographql/graphql-playground-html":"^1.6.24","@creditkarma/thrift-server-core":"^0.15.3","apollo-server-core":"^2.9.13","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.38","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.6","graphql-type-json":"^0.3.1","jsonwebtoken":"^8.5.1","ms":"^2.1.2","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.3","wtfnode":"^0.8.0"},"peerDependencies":{"typeorm":"^0.2.21","graphql":"^14.5.8"},"clientDependencies":{"graphql-voyager":"^1.0.0-rc.28"},"serverDependencies":{"aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","body-parser":"^1.19.0","express":"^4.17.1"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.7.6","@types/aws-lambda":"^8.10.36","@types/aws-serverless-express":"^3.3.2","@types/body-parser":"^1.17.1","@types/express":"^4.17.2","@types/graphql":"^14.5.0","@types/graphql-iso-date":"^3.3.3","@types/graphql-type-json":"^0.3.2","@types/jsonwebtoken":"^8.3.5","@types/koa":"^2.11.0","@types/koa-router":"^7.0.42","@types/ms":"^0.7.31","@types/node":"^12.12.14","@types/uuid":"^3.4.6","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.9.13","aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","body-parser":"^1.19.0","express":"^4.17.1","graphql":"^14.5.8","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","ts-node":"^8.5.4","tslint":"^5.20.1","tslint-config-airbnb":"^5.11.2","typeorm":"^0.2.21","typescript":"^3.9.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","gitHead":"0f54762cdf84a2b43e9f294f1af45c417ce52fcb","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.3.63","_nodeVersion":"16.17.0","_npmVersion":"8.15.0","dist":{"integrity":"sha512-Lelt86o9O882ooupVNxXLjkvO1VLbOGs5o1iAAl7Cb+p9NA2xaczoq66IRpTBlFYYST6OzQvGHA311NQnJj/5Q==","shasum":"f127f90bb4a09fb5f8b5a93cd2d9aa98a84d51c4","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.3.63.tgz","fileCount":303,"unpackedSize":1052838,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDhVlIssoTTeunENkgVaMExVHOicixkel3VOPJ2vjVQwAiBePAs6nmFk4LWa5bf/YaC4xYEEdy0DIJqgmBEUis50kA=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjmkAtACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrFPQ//eRvYcv2doFMmaMDdtzJiR5qmNgPWdOLaN1wTvyZJwyXEf8cT\r\ndB/1dmlXUURhsY1SJalyA2lr6gr05Mni4uLsyPWiu63Klq65yOoRE2mpGdc5\r\nK7ulSn4w7LioIWEL0Nla+Ob3q1RV8VmL07m5BiBj6ry6Ung4tUUcOUX7Wmek\r\nLrDN+x1YRGtPbMx7tAEJl5mM0btlObDli9k36+cZUlXULaqqjQNyz6+/aGeb\r\n3w5rZ3Ba6iq2JhMCAomg+wytlpmvulg+QBfVY2V5hqqCJC2nM4RS4LH10fk3\r\nkPWHEOX7mIlbXeka3bRKetm2bAxUOl4MioO+g+APPljcT1yDQiZ/wplNK8br\r\n+v+Nw3N5Nt7AD4pZX1yde844hTlJcpAIMby15qf9TvdK7EAx/3ImYRqxfg43\r\nE8CQSg/OvwzW9gZ0u0GY6g94qVfrelKq1lspEGKtt2IDEJuGJ5XNFYzTDWCL\r\nywSq93HsXG4ozBC7DcVO/eCZCMYhUUIUwoR7cj6OC6c9MY+CFz68SALoKWVV\r\nw04T1yl5q5jC6YK0iJ6NhPGL+CBh4CCaJRSgN7p5JhQGVptw+tJHDIFo05mQ\r\nfRvurBDzkLiLWWJSZiapW6crZ7dk3xdoppoym8KUykYamWB1p2sNKn039g+d\r\nlL5kfjL+z5TL7bwZIIHXMeCSurg+BBHyTaQ=\r\n=3WVL\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"directories":{},"maintainers":[{"name":"alitelabs","email":"labs@alite-international.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.3.63_1671053357457_0.465085683380976"},"_hasShrinkwrap":false},"0.3.64":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.3.64","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag 0.2.6"},"voyagerVersion":"latest","dependencies":{"@apollographql/graphql-playground-html":"^1.6.24","@creditkarma/thrift-server-core":"^0.15.3","apollo-server-core":"^2.9.13","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.38","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.6","graphql-type-json":"^0.3.1","jsonwebtoken":"^8.5.1","ms":"^2.1.2","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.3","wtfnode":"^0.8.0"},"peerDependencies":{"typeorm":"^0.2.21","graphql":"^14.5.8"},"clientDependencies":{"graphql-voyager":"^1.0.0-rc.28"},"serverDependencies":{"aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","body-parser":"^1.19.0","express":"^4.17.1"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.7.6","@types/aws-lambda":"^8.10.36","@types/aws-serverless-express":"^3.3.2","@types/body-parser":"^1.17.1","@types/express":"^4.17.2","@types/graphql":"^14.5.0","@types/graphql-iso-date":"^3.3.3","@types/graphql-type-json":"^0.3.2","@types/jsonwebtoken":"^8.3.5","@types/koa":"^2.11.0","@types/koa-router":"^7.0.42","@types/ms":"^0.7.31","@types/node":"^12.12.14","@types/uuid":"^3.4.6","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.9.13","aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","body-parser":"^1.19.0","express":"^4.17.1","graphql":"^14.5.8","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","ts-node":"^8.5.4","tslint":"^5.20.1","tslint-config-airbnb":"^5.11.2","typeorm":"^0.2.21","typescript":"^3.9.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","gitHead":"2e5f03760df7cd5d52380724bf99f3d15fbcb6fe","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.3.64","_nodeVersion":"16.17.0","_npmVersion":"8.15.0","dist":{"integrity":"sha512-2IYJDBJ3JE/jYjD9RwHl5fie75OBLqcVNWbxs77xn3A29+VIVXk9Cd/GrZQJICHhtv3cY9mkewZ5rz3UwBLBsQ==","shasum":"edcb93e627e7c08735893221f05068e896f4c482","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.3.64.tgz","fileCount":303,"unpackedSize":1053092,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDR3NUvGOho4tZC4aVhbm3XjbxGFRkok0P8YkUG6oZ4ZAiEA/iROmTKsOw0x53jUF821tveJwnaejy1OoaBPiiuvfBw="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjmu9lACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqU6A//UuERo6f7dZ3f6QjaRoHV7kXiy6XmCuvuCcRWDd7XIYr12i2Q\r\ntYHWXkd6uEXf35fvKxJ++qyTP0q8XemtCEtQngzvneqg0gT0I3AeJh9ynNUF\r\nPLxCbw0//7DuAlccrhVgSE6CmEhRT55A1KQLoaSUtvj9PkYrfcpi0Z7pkksH\r\npxy5jNTpYX6N+1FDTHRBIvfnvbleabKOGW7FYl77v6gwGuV2SwaNttK1unv6\r\ntd01q8gQEWgkpmmv1a7nqbafoH8k9NlehwIQwGOKkIpsOq34Sd9qnm0ekYr1\r\nTNjRSc1g7XZBXKqlM2CUIo+EaCsXbNL1spW5zUxHIhh/uyoQoefQOOierN5W\r\nhIldDTnqCsA7EV0NwklAP40V2grnslqYokpzr3nVx2ff1DL7mCj2MqYGWFuO\r\nQbPGVZKM1kvg00p/lFASd3hmfd1UsP9obxoL+DKVtlB08SRZKf6/nzRSrQ57\r\nPhrGl2+qcbcQkESTJskOshZOMdG7p70YLk5fnXXvUD/F43UC0/Kxmz2dyd16\r\nblUoHZLQaPFvNXX7ooDcbFkLIYBsl5Hhbgj13r1sQP4eCpbXhz2sqsK/GQ2P\r\nQPtgnJytdPEN7sLw+tWy5YmnTM8Z1Z/SV8eGMuSmw1JYx5kLj1zTSc/xRDRX\r\nwRk+KWO9dAJBYdKGiLV7Wb3pineKEv7yKbc=\r\n=74no\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"directories":{},"maintainers":[{"name":"alitelabs","email":"labs@alite-international.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.3.64_1671098212814_0.5853011748565491"},"_hasShrinkwrap":false},"0.3.65":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.3.65","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag 0.2.6"},"voyagerVersion":"latest","dependencies":{"@apollographql/graphql-playground-html":"^1.6.24","@creditkarma/thrift-server-core":"^0.15.3","apollo-server-core":"^2.9.13","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.38","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.6","graphql-type-json":"^0.3.1","jsonwebtoken":"^8.5.1","ms":"^2.1.2","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.3","wtfnode":"^0.8.0"},"peerDependencies":{"typeorm":"^0.2.21","graphql":"^14.5.8"},"clientDependencies":{"graphql-voyager":"^1.0.0-rc.28"},"serverDependencies":{"aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","body-parser":"^1.19.0","express":"^4.17.1"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.7.6","@types/aws-lambda":"^8.10.36","@types/aws-serverless-express":"^3.3.2","@types/body-parser":"^1.17.1","@types/express":"^4.17.2","@types/graphql":"^14.5.0","@types/graphql-iso-date":"^3.3.3","@types/graphql-type-json":"^0.3.2","@types/jsonwebtoken":"^8.3.5","@types/koa":"^2.11.0","@types/koa-router":"^7.0.42","@types/ms":"^0.7.31","@types/node":"^12.12.14","@types/uuid":"^3.4.6","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.9.13","aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","body-parser":"^1.19.0","express":"^4.17.1","graphql":"^14.5.8","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","ts-node":"^8.5.4","tslint":"^5.20.1","tslint-config-airbnb":"^5.11.2","typeorm":"^0.2.21","typescript":"^3.9.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","gitHead":"fcbb00a60f39fb82bdca4c1dfaffc21ea370d07b","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.3.65","_nodeVersion":"16.17.0","_npmVersion":"8.15.0","dist":{"integrity":"sha512-kIGBi5Zh40Q4ysRlel/F2MAGcT245C1tXJu47ofbqqNENLj2VjHmylAbNWr1gjC41amoQJn8DTSBGuEDVSMKvg==","shasum":"528422c33867d8e28295b2cb52d6d9e93d6f6ab8","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.3.65.tgz","fileCount":303,"unpackedSize":1053018,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICISEUNrCRAp9Uq2PiWl421qqkVPCh7x5BtgDbV5sGrqAiBaWtXCsKm/oaT02aGkiiOIYc1RlKNSpUR8b/CGWiToEg=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjmwacACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpkEw//W/ehCYe5kAtGZ96LEya7LpuKOeeFdypoPbS65fr9bMjj5zIz\r\nXWg10QT2tNB5eRneySa3YhR4bB9U0niguPKZFv8qpMlr3gH19kAKypr7YTGw\r\nEBKL895gj8jj4V5MuXbQk9iugViyaJTtrh+z/cfhUhWcGcTLlFSmHc5sAlS4\r\nwp0sd90uws5BCYgKElBVHIzSdp+DtzQ0QqcZdes/oTKrzo5n9nsTR8ttfxKz\r\nbO1bOLGhWJZzmmZs9sGagP2ioQtLK1bi56quTErBXJcsJ2EJRoU8EiOwl0eN\r\nq+PRAjlLnE+IjYRK07K5v5AJKd3tFmrp5ZCPPGu99n31G2TutqRdrDJFBY2K\r\nVl0QajZ/+ocwe4ZKfKY/pXIsRyc81ndnYCTYBYyKV6/0ZjfnjjNvevqG1kar\r\ntWiiHtHsIXKnF0ezlOgytkrkjfWFgB9+dsqqMJQbFpJrSx6sTYVwMfjW/hDg\r\nzf5ExVMyE2fYCHZCPSt5zDQZiDUrcMttvs2zHAtATAxInxV3NN17OLXU7wr0\r\nS/d6gnKslZxI8NcejM+g823ks47HKv0gEKrzl10pUoE9eaujTxJBTw7QC4CW\r\nOy6e8QHNTCWb+7AD4t1x8WX9ZvBLpU0fx/CqRtYLWcbr5uesbmhuvHa+LtRS\r\ngNiQIbZgOLK10y1M59CbcmtawxfdEG7OVWE=\r\n=t2hK\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"directories":{},"maintainers":[{"name":"alitelabs","email":"labs@alite-international.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.3.65_1671104156330_0.31238270099015963"},"_hasShrinkwrap":false},"0.3.66":{"name":"tyx","description":"TyX Core Framework, Serverless back-end in TypeScript for AWS Lambda","version":"0.3.66","license":"MIT","readmeFilename":"README.md","author":{"name":"Alite Labs","email":"labs@alite-international.com"},"repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"tags":["aws","lambda","typescript","serverless","graphql"],"main":"lib/index.js","types":"lib/index.d.ts","source":"src/index.ts","engines":{"node":">=8.10"},"scripts":{"reset":"rm -rf ./node_modules ; rm package-lock.json ; npm i ; npm audit fix","clean":"rm -rf ./lib","prebuild":"rm -rf ./lib","build":"tsc -p . && tslint -p .","watch":"rm -rf ./lib ; tsc -p . --watch","release":"npm run build && npm version patch && git push --follow-tags && npm publish","beta":"npm run build && npm version patch && git push --follow-tags && npm publish --tag 0.2.6"},"voyagerVersion":"latest","dependencies":{"@apollographql/graphql-playground-html":"^1.6.24","@creditkarma/thrift-server-core":"^0.15.3","apollo-server-core":"^2.9.13","apollo-server-module-graphiql":"^1.4.0","exer":"0.0.38","graphql-iso-date":"^3.6.1","graphql-tools":"^4.0.6","graphql-type-json":"^0.3.1","jsonwebtoken":"^8.5.1","ms":"^2.1.2","reflect-metadata":"^0.1.13","typedi":"^0.8.0","uuid":"^3.3.3","wtfnode":"^0.8.0"},"peerDependencies":{"typeorm":"^0.2.21","graphql":"^14.5.8"},"clientDependencies":{"graphql-voyager":"^1.0.0-rc.28"},"serverDependencies":{"aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","body-parser":"^1.19.0","express":"^4.17.1"},"devDependencies":{"@creditkarma/thrift-typescript":"^3.7.6","@types/aws-lambda":"^8.10.36","@types/aws-serverless-express":"^3.3.2","@types/body-parser":"^1.17.1","@types/express":"^4.17.2","@types/graphql":"^14.5.0","@types/graphql-iso-date":"^3.3.3","@types/graphql-type-json":"^0.3.2","@types/jsonwebtoken":"^8.3.5","@types/koa":"^2.11.0","@types/koa-router":"^7.0.42","@types/ms":"^0.7.31","@types/node":"^12.12.14","@types/uuid":"^3.4.6","@types/wtfnode":"^0.7.0","apollo-server-lambda":"^2.9.13","aws-sdk":"^2.585.0","aws-serverless-express":"^3.3.6","body-parser":"^1.19.0","express":"^4.17.1","graphql":"^14.5.8","koa":"^2.11.0","koa-router":"^7.4.0","raw-body":"^2.4.1","ts-node":"^8.5.4","tslint":"^5.20.1","tslint-config-airbnb":"^5.11.2","typeorm":"^0.2.21","typescript":"^3.9.2"},"prettier":{"singleQuote":true,"printWidth":160,"trailingComma":false},"readme":"# TyX Core Framework\n\nServerless back-end framework in TypeScript for AWS Lambda. \nDeclarative dependency injection and event binding.\n\n# Table of Contents\n\n  * [1. Installation](#1-installation)\n  * [2. Examples of Usage](#2-examples-of-usage)\n      - [2.1. Simple service](#21-simple-service)\n      - [2.2. Dependency injection](#22-dependency-injection)\n      - [2.3. Function per service](#23-function-per-service)\n      - [2.4. Remote service](#24-remote-service)\n      - [2.5. Authorization](#25-authorization)\n      - [2.6. Express service](#26-express-service)\n      - [2.7. Error handling](#27-error-handling)\n      - [2.8. Configuration](#28-configuration)\n  * [3. Concepts Overview](#3-concepts-overview)\n      - [3.1. Serverless Environment](#31-serverless-environment)\n      - [3.2. Service](#32-service)\n      - [3.3. Events](#33-events)\n      - [3.4. Container](#34-container)\n      - [3.5. Proxy](#35-proxy)\n  * [4. Data Structures](#4-data-structures)\n      - [4.1. Request Object](#41-request-object)\n      - [4.2. Context Object](#42-context-object)\n  * [5. Service Decorators](#5-service-decorators)\n      - [5.1. @Service decorator](#51-service-decorator)\n      - [5.2. @Inject decorator](#52-inject-decorator)\n      - [5.3. @Proxy decorator](#53-proxy-decorator)\n  * [6. HTTP Decorators](#6-http-decorators)\n      - [6.1. @Get decorator](#61-get-decorator)\n      - [6.2. @Post decorator](#62-post-decorator)\n      - [6.3. @Put decorator](#63-put-decorator)\n      - [6.4. @Delete decorator](#64-delete-decorator)\n      - [6.5. @Patch decorator](#65-patch-decorator)\n      - [6.6. @ContentType decorator](#66-contenttype-decorator)\n      - [6.7. HttpAdapter function](#67-httpadapter-function)\n  * [7. Method Argument Decorators](#7-method-argument-decorators)\n      - [7.1. @PathParam decorator](#71-pathparam-decorator)\n      - [7.2. @PathParams decorator](#72-pathparams-decorator)\n      - [7.3. @QueryParam decorator](#73-queryparam-decorator)\n      - [7.4. @QueryParams decorator](#74-queryparams-decorator)\n      - [7.5. @HeaderParam decorator](#75-headerparam-decorator)\n      - [7.6. @Body decorator](#76-body-decorator)\n      - [7.7. @BodyParam decorator](#77-bodyparam-decorator)\n      - [7.8. @ContextObject decorator](#78-contextobject-decorator)\n      - [7.9. @ContextParam decorator](#79-contextparam-decorator)\n      - [7.10. @RequestObject decorator](#710-requestobject-decorator)\n  * [8. Authorization Decorators](#8-authorization-decorators)\n      - [8.1. @Public decorator](#81-public-decorator)\n      - [8.2. @Private decorator](#82-private-decorator)\n      - [8.3. @Internal decorator](#83-internal-decorator)\n      - [8.4. @Remote decorator](#84-remote-decorator)\n      - [8.5. @Query decorator](#85-query-decorator)\n      - [8.6. @Command decorator](#86-command-decorator)\n      - [8.7. @Invoke decorator](#87-invoke-decorator)\n  * [9. Interfaces and Classes](#9-interfaces-and-classes)\n      - [9.1. Service](#91-service)\n      - [9.2. Proxy](#92-proxy)\n      - [9.3. Containers](#93-containers)\n      - [9.4. Configuration](#94-configuration)\n      - [9.5. Security](#95-security)\n      - [9.6. Logger](#96-logger)\n      - [9.7. Express Service](#97-express-service)\n      \n\n## 1. Installation\n\nInstall module:\n\n`npm install tyx --save`\n\n`reflect-metadata` shim is required:\n\n`npm install reflect-metadata --save`\n\nand make sure to import it before you use tyx:\n\n```typescript\nimport \"reflect-metadata\";\n```\n\nIts important to set these options in `tsconfig.json` file of your project:\n\n```json\n{\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true\n}\n```\n\n## 2. Examples of Usage\n\nThe following examples are constructed to cover all features of TyX.\n\n> TODO: How to build and run the examples\n\n### 2.1. Simple service\n\nThe most basic use scenario is a REST service. It is not required to inherit any base classes; use of the provided decorators is sufficient to bind service methods to corresponding HTTP methods and paths: `@Get`, `@Post`, `@Put`, `@Delete`. Method arguments bind to request elements using decorators as well; `@QueryParam`, `@PathParam` and `@Body` are the core binding.\n\nUse of `@Service()` decorator is mandatory to mark the class as service and enable proper collection of metadata emitted from decorators.\nAs security consideration TyX does not default to public access for service methods, `@Public()` decorator must be explicitly provided otherwise the HTTP binding is effectively disabled.\n\nFor simplicity in this example all files are in the same folder `package.json`, `service.ts`, `function.ts`, `local.ts` and `serverless.yml`\n\n#### Service implementation\n\n```typescript\nimport { Service, Public, PathParam, QueryParam, Body, Get, Post, Put, Delete } from \"tyx\";\n\n@Service()\nexport class NoteService {\n\n    @Public()\n    @Get(\"/notes\")\n    public getAll(@QueryParam(\"filter\") filter?: string) {\n        return { action: \"This action returns all notes\", filter };\n    }\n\n    @Public()\n    @Get(\"/notes/{id}\")\n    public getOne(@PathParam(\"id\") id: string) {\n        return { action: \"This action returns note\", id };\n    }\n\n    @Public()\n    @Post(\"/notes\")\n    public post(@Body() note: any) {\n        return { action: \"Saving note...\", note };\n    }\n\n    @Public()\n    @Put(\"/notes/{id}\")\n    public put(@PathParam(\"id\") id: string, @Body() note: any) {\n        return { action: \"Updating a note...\", id, note };\n    }\n\n    @Public()\n    @Delete(\"/notes/{id}\")\n    public remove(@PathParam(\"id\") id: string) {\n        return { action: \"Removing note...\", id };\n    }\n}\n```\n\n#### Lambda function\n\nServices are plain decorated classes unaware of the specifics of AWS Lambda, the provided `LambdaContainer` class takes care of managing the service and dispatching the trigger events. The container `export()` provides the `handler` entry point for the lambda function. \n\n```typescript\nimport { LambdaContainer, LambdaHandler } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Lambda container and publish the service.\nlet container = new LambdaContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nFor local testing developers can use the `ExpressContainer` class, it exposes routes based on service method decorations. When run in debug mode from an IDE (such as VS Code) it allows convenient debugging experience. \n\n```typescript\nimport { ExpressContainer } from \"tyx\";\nimport { NoteService } from \"./service\";\n\n// Creates an Express container and publish the service.\nlet express = new ExpressContainer(\"tyx-sample1\")\n    .publish(NoteService);\n// Start express server\nexpress.start(5000);\n```\n\nOpen in browser `http://localhost:5000/notes` or `http://localhost:5000/notes/1`.\n\n#### Serverless file\n\nServerless Framework is used to package and deploy functions developed in TyX. Events declared in `serverless.yml` should match those exposed by services published in the function `LambdaContainer`. Missing to declare the event will result in ApiGateway rejecting the request, having events (paths) not bound to any service method will result in the container rejecting the request. \n\n```yaml\nservice: tyx-sample1\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n  \nfunctions:\n  notes-function:\n    handler: function.handler\n    events:\n      - http:\n          path: notes\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: GET\n          cors: true\n      - http:\n          path: notes/{id}\n          method: POST\n          cors: true\n      - http:\n          path: notes/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: notes/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.2. Dependency injection\n\nIt is possible write an entire application as single service but this is rarely justified. It make sense to split the application logic into multiple services each encapsulating related actions and responsibilities.\n\nThis example has a more elaborate structure, separate service API definition and implementation using dependency injection. Two of of the services are for private use within the same container not exposing any event bindings.\n\nThe folder structure used starting with this example:\n- `api/` scripts with service API definition\n- `services/` implementations\n- `functions/` scripts with `LambdaContainer` exporting a handler function\n- `local/` local run using `ExpressContainer`\n- `serverless.yml` Serverless Framework\n\nFollowing examples will further build on this to split services into dedicated functions and then into separate applications (Serverless projects).\n\n#### API definition\n\nTypeScript interfaces have no corresponding representation once code compiles to JavaScript; so to use the interface as service identifier it is also declared and exported as a constant. This is allowed as TypeScript supports declaration merging. \n\nThe services API are returning Promises, this should be a default practice as real life service implementations will certainly use external libraries that are predominantly asynchronous. TypeScript support for `async` and `await` makes the code concise and clean.\n\n- `api/box.ts`\n```typescript \nexport const BoxApi = \"box\";\n\nexport interface BoxApi {\n    produce(type: string): Promise<Box>;\n}\n\nexport interface Box {\n    service: string;\n    id: string;\n    type: string;\n}\n```\n\n- `api/item.ts`\n```typescript \nexport const ItemApi = \"item\";\n\nexport interface ItemApi {\n    produce(type: string): Promise<Item>;\n}\n\nexport interface Item {\n    service: string;\n    id: string;\n    name: string;\n}\n```\n\n- `api/factory.ts`\n```typescript\nimport { Box } from \"./box\";\nimport { Item } from \"./item\";\n\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    produce(boxType: string, itemName: string): Promise<Product>;\n}\n\nexport interface Product {\n    service: string;\n    timestamp: string;\n    box: Box;\n    item: Item;\n}\n```\n\n#### Services implementation\n\nInterfaces are used as service names `@Service(BoxApi)` and `@Inject(ItemApi)` as well as types of the injected properties (dependencies). Dependencies are not part of the service API but its implementation. TypeScript access modifiers (`public`, `private`, `protected`) are not enforced in runtime so injected properties can be declared `protected` as a convention choice.\n\n> Imports of API declarations are skipped in the code samples.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Private()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Private()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\nThe `@Private()` declaration documents that the methods are intended for invocation within the container.\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Lambda function\n\nThe container can host multiple services but only those provided with `publish()` are exposed for external requests. Both `register()` and `publish()` should be called with the service constructor function (class), followed by any constructor arguments if required.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nlet express = new ExpressContainer(\"tyx-sample2\")\n    // Internal services\n    .register(BoxService, \"simple\")\n    .register(ItemService)\n    // Public service\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe Serverless file is only concerned with Lambda functions not the individual TyX services within those functions.\n\n```yaml\nservice: tyx-sample2\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 5\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: INFO\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.3. Function per service\n\nDecoupling the service API and implementation in the previous example allows to split the services into their own dedicated functions. This is useful when service functions need to have fine tuned settings; starting from the basic, memory and timeout, environment variables (configuration) up to IAM role configuration.\n\nWhen deploying services in dedicated functions service-to-service communication is no longer a method call inside the same Node.js process. To allow transparent dependency injection TyX provides for proxy service implementation that using direct Lambda to Lambda function invocations supported by AWS SDK.\n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\nThe only difference from previous example is that `BoxService` and `ItemService` have their method decorated with `@Remote()` instead of `@Private()`. This allows the method to be called outside of the host Lambda functions.\n\n- `services/box.ts`\n```typescript\n@Service(BoxApi)\nexport class BoxService implements BoxApi {\n    private type: string;\n    constructor(type: string) {\n        this.type = type || \"default\";\n    }\n\n    @Remote()\n    public async produce(type: string): Promise<Box> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            type: type || this.type\n        };\n    }\n}\n```\n\n- `services/item.ts`\n```typescript\n@Service(ItemApi)\nexport class ItemService implements ItemApi {\n    @Remote()\n    public async produce(name: string): Promise<Item> {\n        return {\n            service: ServiceMetadata.service(this),\n            id: Utils.uuid(),\n            name\n        };\n    }\n}\n```\n\n- `services/factory.ts`\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi)\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi)\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe provided `LambdaProxy` class takes care of invoking the remote function and converting back the received result or error thrown.\nThe `@Proxy` decorator is mandatory and requires at minimum the name of the proxied service. \n\nThe full signature however is `@Proxy(service: string, application?: string, functionName?: string)`, when not provided `application` defaults to the identifier specified in `LambdaContainer` constructor; `functionName` defaults to `{service}-function`, in this example `box-function` and `item-function` respectively.\n\n- `proxies/box.ts`\n```typescript\n@Proxy(BoxApi)\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n- `proxies/item.ts`\n@Proxy(ItemApi)\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda functions\n\nThe argument passed to `LambdaContainer` is application id and should correspond to the `service` setting in `serverless.yml`. Function-to-function requests within the same application are considered internal, while between different applications as remote. TyX has an authorization mechanism that distinguishes these two cases requiring additional settings. This example is about internal calls, next one covers remote calls. When internal function-to-function calls are used `INTERNAL_SECRET` configuration variable must be set; this is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the requests.\n\n- Box function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(BoxService, \"simple\");\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Item function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    .publish(ItemService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- Factory function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample3\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe following code allows to execute the `FactoryService` in the local container while the proxies will interact with the deployed functions on AWS. \nThe provided `config.ts` provides the needed `environment` variables defined in `serverless.yml`.\n\n- `local/main.ts`\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample3\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n- `local/config.ts`\n```typescript\nexport const Config = {\n    STAGE: \"tyx-sample3-demo\",\n    INTERNAL_SECRET: \"7B2A62EF85274FA0AA97A1A33E09C95F\",\n    LOG_LEVEL: \"INFO\"\n};\n```\n\n\n#### Serverless file\n\nSince internal function-to-function requests are use `INTERNAL_SECRET` is set; this should be an application specific random value (e.g. UUID).\nThe additional setting `REMOTE_SECRET_TYX_SAMPLE4` is to allow remote requests from the next example.\n\nIt is necessary to allow the IAM role to `lambda:InvokeFunction`, of course it is recommended to be more specific about the Resource than in this example.\n\n```yaml\nservice: tyx-sample3\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    REMOTE_SECRET_TYX_SAMPLE4: D718F4BBCC7345749378EF88E660F701\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  box-function:\n    handler: functions/box.handler\n  item-function:\n    handler: functions/item.handler\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.4. Remote service\n\nBuilding upon the previous example this one demonstrates a remote request via `LambdaProxy`. The request is considered remote because involved services are deployed as separate serverless project - the previous example.  \n\nWhen remote function-to-function calls are used `REMOTE_SECRET_(APPID)` and `REMOTE_STAGE_(APPID)` configuration variables must be set. The first is a secret key that both the invoking and invoked function must share so `LambdaContainer` can authorize the calls; the second is `(service)-(stage)` prefix that Serverless Framework prepends to function names by default. \n\n#### API definition\nIdentical to example [2.2. Dependency injection](#22-dependency-injection)\n\n#### Services implementation\n\n`BoxApi` and `ItemApi` are not implemented as services in this example project, those provided and deployed by the previous example will be used via function-to-function calls.\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    @Inject(BoxApi, \"tyx-sample3\")\n    protected boxProducer: BoxApi;\n\n    @Inject(ItemApi, \"tyx-sample3\")\n    protected itemProducer: ItemApi;\n\n    @Public()\n    @Get(\"/product\")\n    public async produce(@QueryParam(\"box\") boxType: string, @QueryParam(\"item\") itemName: string): Promise<Product> {\n        let box: Box = await this.boxProducer.produce(boxType);\n        let item: Item = await this.itemProducer.produce(itemName || \"item\");\n        return {\n            service: ServiceMetadata.service(this),\n            timestamp: new Date().toISOString(),\n            box,\n            item\n        };\n    }\n}\n```\n\n#### Proxy implementation\n\nThe second parameter of `@Proxy()` decorator is provided as the target service is not in this serverless project.\n\n```typescript\n@Proxy(BoxApi, \"tyx-sample3\")\nexport class BoxProxy extends LambdaProxy implements BoxApi {\n    public async produce(type: string): Promise<Box> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n\n@Proxy(ItemApi, \"tyx-sample3\")\nexport class ItemProxy extends LambdaProxy implements ItemApi {\n    public async produce(name: string): Promise<Item> {\n        return this.proxy(this.produce, arguments);\n    }\n}\n```\n\n#### Lambda function\n\nOnly the factory service is exposed as a function.\n\n```typescript\nlet container = new LambdaContainer(\"tyx-sample4\")\n    // Use proxy instead of service implementation\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n```typescript\nimport { Config } from \"./config\";\n\n// Required for accessing Lambda via proxy on AWS\nimport AWS = require(\"aws-sdk\");\nAWS.config.region = \"us-east-1\";\n\nlet express = new ExpressContainer(\"tyx-sample4\")\n    .register(DefaultConfiguration, Config)\n    .register(BoxProxy)\n    .register(ItemProxy)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThe environment variables provide the remote secret and stage for application `tyx-sample3`. In the previous example there is a matching `REMOTE_SECRET_TYX_SAMPLE4` with the same value as `REMOTE_SECRET_TYX_SAMPLE3` here, this pairs the applications. When a remote request is being prepared the secret for the target application is being used; when a remote request is received the secret corresponding to the requesting application is used to authorize the request.\n\n```yaml\nservice: tyx-sample4\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    REMOTE_SECRET_TYX_SAMPLE3: D718F4BBCC7345749378EF88E660F701\n    REMOTE_STAGE_TYX_SAMPLE3: tyx-sample3-demo\n    LOG_LEVEL: DEBUG\n  \n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: product\n          method: GET\n          cors: true\n```\n\n### 2.5. Authorization\n\nTyX supports role-based authorization allowing to control access on service method level. There is no build-in authentication support, for the purpose of this example a hard-coded login service is used. The authorization is using JSON Web Token that are issued and validated by a build-in `Security` service. The container instantiate the default security service if non is registered and use it to validate all requests to non-public service methods.\n\nApart from the `@Public()` permission decorator `@Query<R>()` and `@Command<R>()` are provided to decorate service methods reflecting if the execution results in data retrieval or manipulation (changes).\n\n#### API definition\n\n- `api/app.ts` Definition of application roles interface, used as generic parameter of permission decorators.\n```typescript\nimport { Roles } from \"tyx\";\n\nexport interface AppRoles extends Roles {\n    Admin: boolean;\n    Manager: boolean;\n    Operator: boolean;\n}\n```\n\n- `api/login.ts` Login service API\n```typescript\nexport const LoginApi = \"login\";\n\nexport interface LoginApi {\n    login(userId: string, password: string): Promise<string>;\n}\n```\n\n- `api/factory.ts` Extended factory API\n```typescript\nexport const FactoryApi = \"factory\";\n\nexport interface FactoryApi {\n    // Admin only\n    reset(userId: string): Promise<Response>;\n    createProduct(userId: string, productId: string, name: string): Promise<Confirmation>;\n    removeProduct(userId: string, productId: string): Promise<Confirmation>;\n\n    // Admin & Manager\n    startProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n    stopProduction(userId: string, role: string, productId: string, order: any): Promise<Confirmation>;\n\n    // Operator\n    produce(userId: string, role: string, productId: string): Promise<Item>;\n\n    // Public\n    status(userId: string, role: string): Promise<Status>;\n}\n\nexport interface Response {\n    userId: string;\n    role: string;\n    status: string;\n}\n\nexport interface Product {\n    productId: string;\n    name: string;\n    creator: string;\n    production: boolean;\n}\n\nexport interface Confirmation extends Response {\n    product: Product;\n    order?: any;\n}\n\nexport interface Item extends Response {\n    product: Product;\n    itemId: string;\n    timestamp: string;\n}\n\nexport interface Status extends Response {\n    products: Product[];\n}\n```\n\n#### Login implementation\n\nThe login service provides a public entry point for users to obtain an access token. The injected `Security` service is always present in the container.\n\n```typescript\n@Service(LoginApi)\nexport class LoginService implements LoginApi {\n\n    @Inject(Security)\n    protected security: Security;\n\n    @Public()\n    @Post(\"/login\")\n    @ContentType(\"text/plain\")\n    public async login(\n            @BodyParam(\"userId\") userId: string,\n            @BodyParam(\"password\") password: string): Promise<string> {\n        let role: string = undefined;\n        switch (userId) {\n            case \"admin\": role = password === \"nimda\" && \"Admin\"; break;\n            case \"manager\": role = password === \"reganam\" && \"Manager\"; break;\n            case \"operator\": role = password === \"rotarepo\" && \"Operator\"; break;\n        }\n        if (!role) throw new Unauthorized(\"Unknown user or invalid password\");\n       return await this.security.issueToken({ subject: \"user:internal\", userId, role });\n    }\n}\n```\n\n#### Service implementation\n\nMethods `reset()`, `createProduct()` and `removeProduct()` are decorated with `@Command<AppRoles>({ Admin: true, Manager: false, Operator: false })` allowing only Admin users to invoke them via the HTTP bindings specified with `@Post()` and `@Delete()` decorators.\n\nMethods `startProduction()` and `stopProduction()` are allowed to Admin and Manager role; both bind to the same path `@Put(\"/product/{id}\", true)` however the second param set to `true` instructs the container that `Content-Type` header will have an additional parameter `domain-model` equal to the method name so to select the desired action, e.g. `Content-Type: application/json;domain-model=startProduction`.\n\nMethod `produce()` is allowed for all three roles but not for public access. Public access is allowed to method `status()` with `@Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })`.\n\nWhen the userId, role or other authorization attributes are needed in method logic `@ContextParam(\"auth.{param}\")` can be used to bind the arguments. Other option is to use `@ContextObject()` and so get the entire context object as single attribute.\n\n> Having a service state `products` is for example purposes only, Lambda functions must persist the state in cloud services (e.g. DynamoDB).\n\n```typescript\n@Service(FactoryApi)\nexport class FactoryService implements FactoryApi {\n\n    private products: Record<string, Product> = {};\n\n    // Admin only\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/reset\")\n    public async reset(\n        @ContextParam(\"auth.userId\") userId: string): Promise<Response> {\n        this.products = {};\n        return { userId, role: \"Admin\", status: \"Reset\" };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Post(\"/product\")\n    public async createProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @BodyParam(\"id\") productId: string,\n        @BodyParam(\"name\") name: string): Promise<Confirmation> {\n\n        if (this.products[productId]) throw new BadRequest(\"Duplicate product\");\n        let product = { productId, name, creator: userId, production: false, orders: [] };\n        this.products[productId] = product;\n        return { userId, role: \"Admin\", status: \"Create product\", product };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: false, Operator: false })\n    @Delete(\"/product/{id}\")\n    public async removeProduct(\n        @ContextParam(\"auth.userId\") userId: string,\n        @PathParam(\"id\") productId: string): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        delete this.products[productId];\n        return { userId, role: \"Admin\", status: \"Remove product\", product };\n    }\n\n    // Admin & Manager\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async startProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = true;\n        product.orders.push(order);\n        return { userId, role, status: \"Production started\", product, order };\n    }\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: false })\n    @Put(\"/product/{id}\", true)\n    public async stopProduction(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string,\n        @Body() order: any): Promise<Confirmation> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        product.production = false;\n        product.orders.push(order);\n        return { userId, role, status: \"Production stopped\", product, order };\n    }\n\n    // + Operator\n\n    @Command<AppRoles>({ Admin: true, Manager: true, Operator: true })\n    @Get(\"/product/{id}\")\n    public async produce(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string,\n        @PathParam(\"id\") productId: string): Promise<Item> {\n\n        let product = this.products[productId];\n        if (!product) throw new NotFound(\"Product not found\");\n        if (!product.production) throw new BadRequest(\"Product not in production\");\n        let item: Item = {\n            userId, role,\n            status: \"Item produced\",\n            product,\n            itemId: Utils.uuid(),\n            timestamp: new Date().toISOString()\n        };\n        return item;\n    }\n\n    @Query<AppRoles>({ Public: true, Admin: true, Manager: true, Operator: true })\n    @Get(\"/status\")\n    public async status(\n        @ContextParam(\"auth.userId\") userId: string,\n        @ContextParam(\"auth.role\") role: string): Promise<Status> {\n\n        let products = [];\n        Object.keys(this.products).forEach(k => products.push(this.products[k]));\n        return { userId, role, status: \"Status\", products };\n    }\n}\n```\n\n\n#### Lambda functions\n\nLogin and Factory services are independent so can be deployed as separate functions.\n\n- `services/factory.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(FactoryService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `services/login.ts` \n```typescript\nlet container = new LambdaContainer(\"tyx-sample5\")\n    .publish(LoginService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nThe container constructor accepts an additional argument that is path prefix for all exposed routes. In this case `/demo` match how Api Gateway by default will include the stage name in the path.\n\n```typescript\nimport { Config } from \"./config\";\n\nlet express = new ExpressContainer(\"tyx-sample5\", \"/demo\")\n    .register(DefaultConfiguration, Config)\n    .publish(LoginService)\n    .publish(FactoryService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nWhen using authorization it is necessary to provide a `HTTP_SECRET` that is used to sign and verify the web tokens as well as `HTTP_TIMEOUT` how long the tokens are valid.\n\n```yaml\nservice: tyx-sample5\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    HTTP_SECRET: 3B2709157BD8444BAD42DE246D41BB35\n    HTTP_TIMEOUT: 2h\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  login-function:\n    handler: functions/login.handler\n    events:\n      - http:\n          path: login\n          method: POST\n          cors: true\n  factory-function:\n    handler: functions/factory.handler\n    events:\n      - http:\n          path: reset\n          method: POST\n          cors: true\n      - http:\n          path: product\n          method: POST\n          cors: true\n      - http:\n          path: product/{id}\n          method: DELETE\n          cors: true\n      - http:\n          path: product/{id}\n          method: PUT\n          cors: true\n      - http:\n          path: product/{id}\n          method: GET\n          cors: true\n      - http:\n          path: status\n          method: GET\n          cors: true\n```\n\n#### Token sample\n\nWhen posting to example `LoginService` at `/demo/login` with json body `{ userId: \"admin\", password: \"nimda\" }` a token is received as plain text:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJvaWQiOiJhZG1pbiIsInJvbGUiOiJBZG1pbiIsImlhdCI6MTUwODk0NDI5NywiZX\nhwIjoxNTA4OTUxNDk3LCJhdWQiOiJ0eXgtc2FtcGxlNSIsImlzcyI6InR5eC1zYW1w\nbGU1Iiwic3ViIjoidXNlcjppbnRlcm5hbCIsImp0aSI6ImI4N2U1MDYyLTYwNjItND\nk0Ny1iMTU1LWZmNzA0NzBhMTEzZCJ9.\nb8H27N26QKFbFofuMPd1PGQHG7UeB5J1FIoQIte-dss\n```\n\nDecoded it contains the minimum info for the security service:\n\n- `oid` is user identifier\n- `role` application role\n- `iat` issued-at timestamp\n- `exp` expiry timestamp\n- `aud` application id the token is intended to\n- `iss` application id issuing the token\n- `sub` subject / token type\n- `jti` unique token id \n\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n{\n  \"oid\": \"admin\",\n  \"role\": \"Admin\",\n  \"iat\": 1508944297,\n  \"exp\": 1508951497,\n  \"aud\": \"tyx-sample5\",\n  \"iss\": \"tyx-sample5\",\n  \"sub\": \"user:internal\",\n  \"jti\": \"b87e5062-6062-4947-b155-ff70470a113d\"\n}\n```\n\n### 2.6. Express service\n\nExpress is an established node.js web framework and there is a wealth of third party middleware packages that may not be available in other form. The `ExpressService` base class uses [aws-serverless-express](https://github.com/awslabs/aws-serverless-express) to host an Express application. This is not intended to host existing Express applications but more as a solution to bridge the gap for specific functionalities, for example use [Passport.js](http://www.passportjs.org/) to implement user authentication.\n\n#### API definition\n\nService methods delegating to Express must have a signature `method(ctx: Context, req: HttpRequest): Promise<HttpResponse>`, the service can have ordinary methods as well.\n\n```typescript\nexport const ExampleApi = \"example\";\n\nexport interface ExampleApi {\n    hello(): string;\n    onGet(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    onPost(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    other(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n}\n```\n\n#### Service implementation\n\nMultiple routes delegated to Express for processing can be declared with decorators over a single method, such as `other()` in the example or over dedicated methods such as `onGet()` and `onPost()` to allow for logic preceding or following the Express processing. Presence of `@ContentType(\"RAW\")` is required to pass the result verbatim to the user (`statusCode`, `headers`, `body` as generated by Express) otherwise the returned object will be treated as a json body. \n\nThe base class requires to implement the abstract method `setup(app: Express, ctx: Context, req: HttpRequest): void` that setup the Express app to be used for request processing. Each instance of the express app is used for a single request, no state can be maintained inside Lambda functions.\n\n```typescript\nimport BodyParser = require(\"body-parser\");\n\n@Service(ExampleApi)\nexport class ExampleService extends ExpressService implements ExampleApi {\n\n    @Public()\n    @Get(\"/hello\")\n    @ContentType(\"text/plain\")\n    public hello(): string {\n        return \"Express service ...\";\n    }\n\n    @Public()\n    @Get(\"/app\")\n    @ContentType(\"RAW\")\n    public async onGet(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Post(\"/app\")\n    @ContentType(\"RAW\")\n    public async onPost(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    @Public()\n    @Put(\"/app\")\n    @Delete(\"/app/{id}\")\n    @ContentType(\"RAW\")\n    public async other(@ContextObject() ctx: Context, @RequestObject() req: HttpRequest): Promise<HttpResponse> {\n        return super.process(ctx, req);\n    }\n\n    protected setup(app: Express, ctx: Context, req: HttpRequest): void {\n        app.register(BodyParser.json());\n\n        app.get(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.post(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.put(\"/app\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n        app.delete(\"/app/:id\", (xreq, xres) => this.flush(xreq, xres, ctx, req));\n    }\n\n    private flush(xreq: Request, xres: Response, ctx: Context, req: HttpRequest) {\n        let result = {\n            msg: `Express ${req.method} method`,\n            path: xreq.path,\n            method: xreq.method,\n            headers: xreq.headers,\n            params: xreq.params,\n            query: xreq.query,\n            body: xreq.body,\n            lambda: { ctx, req }\n        };\n        xres.send(result);\n    }\n}\n```\n\n#### Lambda function\n```typescript\nlet container = new LambdaContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Express container\n\nApplications containing express services can be run with the `ExpressContainer`, the container express instance and the internal service instance remain completely separate.\n\n```typescript\nlet express = new ExpressContainer(\"tyx-sample6\")\n    .publish(ExampleService);\n\nexpress.start(5000);\n```\n\n#### Serverless file\n\nThere no special requirements for functions hosting Express services.\n\n```yaml\nservice: tyx-sample6\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n  \nfunctions:\n  example-function:\n    handler: functions/example.handler\n    events:\n      - http:\n          path: hello\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: GET\n          cors: true\n      - http:\n          path: app\n          method: POST\n          cors: true\n      - http:\n          path: app\n          method: PUT\n          cors: true\n      - http:\n          path: app/{id}\n          method: DELETE\n          cors: true\n```\n\n### 2.7. Error handling\n\nError handling is implemented in TyX containers to ensure both explicitly thrown errors and runtime errors are propagated in unified format to the calling party. Classes corespnding to standard HTTP error responses are provided: \n\n- `400 BadRequest`\n- `401 Unauthorized`\n- `403 Forbidden`\n- `404 NotFound`\n- `409 Conflict`\n- `500 InternalServerError`\n- `501 NotImplemented`\n- `503 ServiceUnavailable`\n\n#### API definition\n\n- `api/calculator.ts` combined service\n```typescript\nexport const CalculatorApi = \"calculator\";\n\nexport interface CalculatorApi {\n    mortgage(amount: any, nMonths: any, interestRate: any, precision: any): Promise<MortgageResponse>;\n    missing(req: any): Promise<number>;\n    unhandled(req: any): Promise<number>;\n}\n\nexport interface MortgageResponse {\n    monthlyPayment: number;\n    total: number;\n    totalInterest: number;\n}\n```\n\n- `api/mortgage.ts` mortgage calculation service\n```typescript\nexport const MortgageApi = \"mortgage\";\n\nexport interface MortgageApi {\n    calculate(amount: number, nMonths: number, interestRate: number, precision: number): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to missing function\n```typescript\nexport const MissingApi = \"missing\";\n\nexport interface MissingApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n- `api/missing.ts` used for proxy to a function throwing unhandled exception\n```typescript\nexport const UnhandledApi = \"unhandled\";\n\nexport interface UnhandledApi {\n    calculate(req: any): Promise<number>;\n}\n```\n\n\n#### Services implementation\n\n- `services/calculator.ts` validates that body parameters are present and expected type.\n```typescript\n@Service(CalculatorApi)\nexport class CalculatorService implements CalculatorApi {\n\n    @Inject(MortgageApi)\n    protected mortgageService: MortgageApi;\n\n    @Inject(MissingApi)\n    protected missingService: MissingApi;\n\n    @Inject(UnhandledApi)\n    protected unhandledService: UnhandledApi;\n\n    @Public()\n    @Post(\"/mortgage\")\n    public async mortgage(@BodyParam(\"amount\") amount: any,\n        @BodyParam(\"nMonths\") nMonths: any,\n        @BodyParam(\"interestRate\") interestRate: any,\n        @BodyParam(\"precision\") precision: any): Promise<MortgageResponse> {\n\n        let _amount = Number.parseFloat(amount);\n        let _nMonths = Number.parseFloat(nMonths);\n        let _interestRate = Number.parseFloat(interestRate);\n        let _precision = precision && Number.parseFloat(precision);\n\n        // Type validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (!Number.isFinite(_amount)) errors.detail(\"amount\", \"Amount required and must be a number, got: {input}.\", { input: amount || null });\n        if (!Number.isInteger(_nMonths)) errors.detail(\"nMonths\", \"Number of months required and must be a integer, got: {input}.\", { input: nMonths || null });\n        if (!Number.isFinite(_interestRate)) errors.detail(\"interestRate\", \"Interest rate required and must be a number, got: {input}.\", { input: interestRate || null });\n        if (_precision && !Number.isInteger(_precision)) errors.detail(\"precision\", \"Precision must be an integer, got: {input}.\", { input: precision || null });\n        if (errors.count()) throw errors.reason(\"calculator.mortgage.validation\", \"Parameters validation failed\").create();\n\n        let monthlyPayment = await this.mortgageService.calculate(_amount, _nMonths, _interestRate, _precision);\n\n        return {\n            monthlyPayment,\n            total: monthlyPayment * _nMonths,\n            totalInterest: (monthlyPayment * _nMonths) - _amount\n        };\n    }\n\n    @Public()\n    @Post(\"/missing\")\n    public async missing(@Body() req: any): Promise<number> {\n        return this.missingService.calculate(req);\n    }\n\n    @Public()\n    @Post(\"/unhandled\")\n    public async unhandled(@Body() req: any): Promise<number> {\n        return this.unhandledService.calculate(req);\n    }\n}\n```\n\n- `services/mortgage.ts` simple mortgage monthly payment calculator service, `BadRequest.builder()` returns a instance of `ApiErrorBuilder` allowing to progressively compose validation errors; in this case inputs are expected to be positive numbers.\n```typescript\n@Service(MortgageApi)\nexport class MortgageService implements MortgageApi {\n\n    @Remote()\n    public async calculate(amount: number, nMonths: number, interestRate: number, precision: number = 5): Promise<number> {\n\n        // Range validation\n        let errors: ApiErrorBuilder = BadRequest.builder();\n        if (amount <= 0) errors.detail(\"amount\", \"Amount must be grater than zero.\" );\n        if (nMonths <= 0) errors.detail(\"nMonths\", \"Number of months  must be grater than zero.\");\n        if (interestRate <= 0) errors.detail(\"interestRate\", \"Interest rate must be grater than zero.\");\n        if (errors.count()) throw errors.reason(\"mortgage.calculate.validation\", \"Invalid parameters values\").create();\n\n        interestRate = interestRate / 100 / 12;\n        let x = Math.pow(1 + interestRate, nMonths);\n        return +((amount * x * interestRate) / (x - 1)).toFixed(precision);\n    }\n}\n```\n\n#### Proxy implementation\n\n- `proxies/mortgage.ts` Mortgage calculator is deployed as a dedicated Lambda function, to demonstrate that errors just as the return value is transparently passed.\n\n```typescript\n@Proxy(MortgageApi)\nexport class MortgageProxy extends LambdaProxy implements MortgageApi {\n    public calculate(amount: any, nMonths: any, interestRate: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/missing.ts` Calling the proxy results in error due to non-existence of the target function\n\n```typescript\n@Proxy(MissingApi)\nexport class MissingProxy extends LambdaProxy implements MissingApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n- `proxies/unhandled.ts` Calling the proxy results in unhandled error\n\n```typescript\n@Proxy(UnhandledApi)\nexport class UnhandledProxy extends LambdaProxy implements UnhandledApi {\n    public calculate(req: any): Promise<number> {\n        return this.proxy(this.calculate, arguments);\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/calculator.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .register(MortgageProxy)\n    .publish(CalculatorService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/mortgage.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample7\")\n    .publish(MortgageService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n- `functions/unhandled.ts` Unhandled error is thrown instead using `callback(err, null)` for handled errors\n```typescript\nexport function handler(event: any, ctx: any, callback: (err, data) => void) {\n    throw new Error(\"Not Implemented\");\n}\n```\n\n#### Serverless file\n\n```yaml\nservice: tyx-sample7\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    INTERNAL_SECRET: 7B2A62EF85274FA0AA97A1A33E09C95F\n    INTERNAL_TIMEOUT: 5s\n    LOG_LEVEL: DEBUG\n  \n  # permissions for all functions\n  iamRoleStatements: \n    - Effect: Allow\n      Action:\n        - lambda:InvokeFunction\n      Resource: \"arn:aws:lambda:${opt:region, self:provider.region}:*:*\"\n\nfunctions:\n  mortgage-function:\n    handler: functions/mortgage.handler\n  unhandled-function:\n    handler: functions/unhandled.handler\n  calculator-function:\n    handler: functions/calculator.handler\n    events:\n      - http:\n          path: mortgage\n          method: POST\n          cors: true\n      - http:\n          path: missing\n          method: POST\n          cors: true\n      - http:\n          path: unhandled\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/mortgage` a valid request:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"2\"\n}\n```\nresponse is received:\n```json\n{\n    \"monthlyPayment\": 1047.3,\n    \"total\": 15709.5,\n    \"totalInterest\": 709.5\n}\n```\n\nWhen any of required inputs is missing or not a number:\n```json\n{\n    \"amount\": \"15000\",\n    \"interestRate\": \"zero\",\n    \"precision\": \"2\"\n}\n```\nHTTP 404 Bad Request is received with the error as json body:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Parameters validation failed\",\n\t\"reason\": {\n\t\t\"code\": \"calculator.mortgage.validation\",\n\t\t\"message\": \"Parameters validation failed\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"nMonths\",\n\t\t\"message\": \"Number of months required and must be a integer, got: null.\",\n\t\t\"params\": {\n\t\t\t\"input\": null\n\t\t}\n\t}, {\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate required and must be a number, got: zero.\",\n\t\t\"params\": {\n\t\t\t\"input\": \"zero\"\n\t\t}\n\t}],\n\t\"stack\": \"BadRequest: Parameters validation failed\\n    at CalculatorService.<anonymous> (/var/task/services/calculator.js:44:103)\\n    at next (native)\\n    at /var/task/services/calculator.js:19:71\\n    at __awaiter (/var/task/services/calculator.js:15:12)\\n    at CalculatorService.mortgage (/var/task/services/calculator.js:28:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:202:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nSending a negative value will return an error generated in `MortgageService`:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"-7\",\n    \"precision\": \"2\"\n}\n```\nError repsonse:\n```json\n{\n\t\"code\": 400,\n\t\"message\": \"Invalid parameters values\",\n\t\"proxy\": true,\n\t\"reason\": {\n\t\t\"code\": \"mortgage.calculate.validation\",\n\t\t\"message\": \"Invalid parameters values\"\n\t},\n\t\"details\": [{\n\t\t\"code\": \"interestRate\",\n\t\t\"message\": \"Interest rate must be grater than zero.\"\n\t}],\n\t\"stack\": \"BadRequest: Invalid parameters values\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:34:99)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\",\n\t\"__class__\": \"BadRequest\"\n}\n```\n\nOn purpose there is no check on valid range for precision to demonstrate handling of runtime errors:\n```json\n{\n    \"amount\": \"15000\",\n    \"nMonths\": \"15\",\n    \"interestRate\": \"7\",\n    \"precision\": \"25\"\n}\n```\nResponds with 500 Internal Server Error:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\"proxy\": true,\n\t\"cause\": {\n\t\t\"stack\": \"RangeError: toFixed() digits argument must be between 0 and 20\\n    at Number.toFixed (native)\\n    at MortgageService.<anonymous> (/var/task/services/mortgage.js:37:61)\\n    at next (native)\\n    at /var/task/services/mortgage.js:16:71\\n    at __awaiter (/var/task/services/mortgage.js:12:12)\\n    at MortgageService.calculate (/var/task/services/mortgage.js:24:16)\\n    at /var/task/node_modules/tyx/core/container/instance.js:173:47\\n    at next (native)\\n    at /var/task/node_modules/tyx/core/container/instance.js:7:71\\n    at __awaiter (/var/task/node_modules/tyx/core/container/instance.js:3:12)\",\n\t\t\"message\": \"toFixed() digits argument must be between 0 and 20\",\n\t\t\"__class__\": \"RangeError\"\n\t},\n\t\"stack\": \"InternalServerError: toFixed() digits argument must be between 0 and 20\\n    at LambdaContainer.<anonymous> (/var/task/node_modules/tyx/aws/container.js:49:56)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/container.js:5:65)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/missing` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\"cause\": {\n\t\t\"stack\": \"ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)\\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:45:8)\\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)\\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)\\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)\",\n\t\t\"message\": \"Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\",\n\t\t\"code\": \"ResourceNotFoundException\",\n\t\t\"name\": \"ResourceNotFoundException\",\n\t\t\"time\": \"2017-10-31T08:48:27.688Z\",\n\t\t\"requestId\": \"435de987-be18-11e7-b667-657e489d6573\",\n\t\t\"statusCode\": 404,\n\t\t\"retryable\": false,\n\t\t\"retryDelay\": 75.5332334968972,\n\t\t\"__class__\": \"Error\"\n\t},\n\t\"stack\": \"InternalServerError: Function not found: arn:aws:lambda:us-east-1:9999999999:function:tyx-sample7-demo-missing-function\\n    at MissingProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:45:52)\\n    at throw (native)\\n    at rejected (/var/task/node_modules/tyx/aws/proxy.js:5:65)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\nPosting to `/demo/unhandled` with any json body will result in:\n```json\n{\n\t\"code\": 500,\n\t\"message\": \"RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\",\n\t\"stack\": \"InternalServerError: RequestId: 726809f7-be19-11e7-bdb3-c7331d9214c8 Process exited before completing request\\n    at UnhandledProxy.<anonymous> (/var/task/node_modules/tyx/aws/proxy.js:52:52)\\n    at next (native)\\n    at fulfilled (/var/task/node_modules/tyx/aws/proxy.js:4:58)\\n    at process._tickDomainCallback (internal/process/next_tick.js:135:7)\",\n\t\"__class__\": \"InternalServerError\"\n}\n```\n\n### 2.8. Configuration\n\nTyX containers require the presence of the Configuration service, if one is not provided a default implementation is being used. In this example the Configuration service is extended with properties relevant to the simple timestamp service.\n\n#### API definition\n\nRecommended convention is to name extension as ConfigApi and ConfigService. The API must extend the `Configuration` interface, so it merged constant (service name) equals `Configuration` as well.\n\n- `api/config.ts` extended configuration\n```typescript\nexport const ConfigApi = Configuration;\n\nexport interface ConfigApi extends Configuration {\n    timestampSecret: string;\n    timestampStrength: number;\n}\n```\n\n- `api/timestamp.ts` example timestamp service\n```typescript\nexport interface TimestampApi {\n    issue(data: any): TimestampResult;\n    verify(input: TimestampResult): TimestampResult;\n}\n\nexport interface TimestampResult {\n    id: string;\n    timestamp: string;\n    hash: string;\n    signature: string;\n    data: any;\n    valid?: boolean;\n    error?: string;\n}\n```\n\n#### Config service implementation\n\nThe implementation extends the provided `BaseConfiguration` class that is simple wrapper around a json object `this.config` which is `process.env` by default. This approach uses Environment Variables of Lambda functions that are also supported by the Serverless Framework, so configurations can be modified via AWS Console or API without a need to redeploy the function. Developers can directly implement the `Configuration` interface to use different storage.\n\n```typescript\n@Service(ConfigApi)\nexport class ConfigService extends BaseConfiguration implements ConfigApi {\n\n    constructor(config?: any) {\n        super(config);\n    }\n\n    get timestampSecret() { return this.config.TIMESTAMP_SECRET; }\n\n    get timestampStrength() { return parseInt(this.config.TIMESTAMP_STRENGTH || 0); }\n}\n```\n\n#### Timestamp service implementation\n\nExample timestamp service based on SHA256.\n\n```typescript\n@Service(TimestampApi)\nexport class TimestampService extends BaseService implements TimestampApi {\n\n    @Inject(ConfigApi)\n    protected config: ConfigApi;\n\n    @Public()\n    @Post(\"/issue\")\n    public issue( @Body() data: any): TimestampResult {\n        let result = { id: UUID(), timestamp: new Date().toISOString(), hash: null, signature: null, data };\n        let text = JSON.stringify(data);\n        [result.hash, result.signature] = this.sign(result.id, result.timestamp, text);\n        return result;\n    }\n\n    @Public()\n    @Post(\"/verify\")\n    public verify( @Body() input: TimestampResult): TimestampResult {\n        if (!input.id || !input.timestamp || !input.hash || !input.signature || !input.data)\n            throw new BadRequest(\"Invalid input format\");\n        let hash: string, signature: string;\n        [hash, signature] = this.sign(input.id, input.timestamp, JSON.stringify(input.data));\n        if (hash !== input.hash) input.error = \"Hash mismatch\";\n        else if (signature !== input.signature) input.error = \"Invalid signature\";\n        else input.valid = true;\n        return input;\n    }\n\n    private sign(id: string, timestamp: string, input: string): [string, string] {\n        if (!this.config.timestampSecret) throw new InternalServerError(\"Signature secret not configured\");\n        if (!this.config.timestampStrength) throw new InternalServerError(\"Signature strength not configured\");\n        let hash: string = SHA256(input || \"\");\n        let signature: string = id + \"/\" + timestamp + \"/\" + hash;\n        for (let i = 0; i < this.config.timestampStrength; i++)\n            signature = SHA256(signature + \"/\" + i + \"/\" + this.config.timestampSecret);\n        return [hash, signature];\n    }\n}\n```\n\n#### Lambda function\n\n- `functions/timestamp.ts`\n```typescript\nlet container = new LambdaContainer(\"tyx-sample8\")\n    .register(ConfigService)\n    .publish(TimestampService);\n\nexport const handler: LambdaHandler = container.export();\n```\n\n#### Serverless file\n\nThe two configuration parameters are defined on function level where they are used. There is a limitation that \"total size of the set does not exceed 4 KB\" per function so better define variables under `provider` only when used by all or significant number of functions.\n\n```yaml\nservice: tyx-sample8\n\nprovider:\n  name: aws\n  region: us-east-1\n  stage: demo\n  runtime: nodejs6.10\n  memorySize: 128\n  timeout: 10\n  \n  environment:\n    STAGE: ${self:service}-${opt:stage, self:provider.stage}\n    LOG_LEVEL: DEBUG\n\nfunctions:\n  timestamp-function:\n    handler: functions/timestamp.handler\n    environment:\n      TIMESTAMP_SECRET: F72001057DDA40D3B7B81E7BF06CF495\n      TIMESTAMP_STRENGTH: 3\n    events:\n      - http:\n          path: issue\n          method: POST\n          cors: true\n      - http:\n          path: verify\n          method: POST\n          cors: true\n```\n\n### Sample responses\n\nWhen posting to `/demo/issue` a json object:\n```json\n{\n    \"from\": \"tyx\",\n    \"to\": \"world\",\n    \"message\": \"Hello World ...\"\n}\n```\nsigned timestamp is received:\n```json\n{\n    \"id\": \"c43c1de9-9561-47d3-8aed-10e4e7080b59\",\n    \"timestamp\": \"2017-10-31T10:48:03.903Z\",\n    \"hash\": \"760c891dd1061a843bf9a778e2fb42d28ea6aa57654474cd176ee5385c674875\",\n    \"signature\": \"a3d71713bca7830d9f8b10f7841758db0e7bfd0bfcb2a450fd0caa3d8a72eca2\",\n    \"data\": {\n        \"from\": \"tyx\",\n        \"to\": \"world\",\n        \"message\": \"Hello World ...\"\n    }\n}\n```\n\n\n## 3. Concepts Overview\n\nTyX Core Framework aims to provide a programming model for back-end serverless solutions by leveraging TypeScript support for object oriented programming. TyX addresses how to write and structure the application back-end into services deployed as Lambda functions. \n\nDecorators are extensively used while inheritance from base classes is minimized. Services so written are abstracted from details how HTTP events arrive, how the response is propagated back and the internal routing in case of multiple events being served by the hosting Lambda function. These responsibilities are handled by a Container specific to the hosting environment (Lambda). As proof-of-concept and to serve as development tool an Express based container is provided allowing to run the unmodified services code.\n\nTyX was developed with intent to be used together with [Serverless Framework](https://serverless.com/framework/) that provides rapid deployment. There is no direct dependency on the Serverless Framework so developers can opt for alternative deployment tools.\n\n### 3.1. Serverless Environment\n\nAWS Lambda and API Gateway are the core component of [AWS Serverless Platform](https://aws.amazon.com/serverless). API Gateway takes most of the responsibilities traditionally handled by HTTP Web Servers (e.g. Apache, nginx, IIS ...), it is the entry point for HTTP requests; however it does not directly host or manage code responsible for handling those requests. AWS Lambda is a compute service for running code without provisioning or managing servers. Lambda functions react on events, API Gateway being one of the supported sources. On each HTTP request arriving on API Gateway an event object is dispatched to an instance of a Lambda function, on its completion the function provides the response (statusCode, headers, body).\n\nLambda functions are subject to limitation on memory and allowed execution time, and are inherently stateless. AWS Lambda may create, destroy or reuse instances of the Lambda function to accommodate the demand (traffic). The function instance is not aware of its life-cycle. At most it can detect when handler function is first loaded but there is no notification/events when the instance is to be frozen for reuse or about to be destroyed. This prevents any meaningful internal state or cache as the function is not a continuously running process. Limited access to the file system is allowed but should not be used with assumption that stored files will be available for the next request; certainly not to run a local database.\n\nNumber of concurrently running function instances is also limited (per AWS account). Developers have no control over the max number of instances a given function can have, which is a challenge when other services or resources used by the function (e.g. database) can not support or scale to match the concurrent requests. Serverless concept removes the need to manage servers or containers for the function (business logic) execution but this does not cover the management of services those functions use. For example S3 most likely can accommodate any load of object access and manipulation concurrent Lambda functions can generate; on the contrary databases usually have limits on concurrent connections and/or the allowed read/write throughput. The Serverless environment may look very restricted and even hostile toward some traditional practices (like the mentioned in-memory caching, or local disk databases). Lambda functions are not intended to serve static files or render HTML content as with MVC frameworks, handling file uploads is also best avoided. \n\nTyX framework does not shield the developer from the specifics and challenges of the serverless architecture, nor does it attempt to abstract the limitations of the execution environment. \n\n### 3.2. Service\n\nServices are the building block of application back-end and together with dependency injection provides for structured and flexible code organization. A service can expose only a single method with event binding, and if hosted in a dedicated Lambda function will abide to the single responsibility principle. However it may group together methods corresponding to related actions or entities, following microservice principles. TyX does not enforce a specific style or paradigm; a Lambda function can host arbitrary number of services each with its own event bindings.\n\nTraditionally web frameworks especially those based on MVC pattern make a distinction between the concepts of Service and Controller. As TyX is aimed at back-end service layer only the notion of Service is provided; a Service having event bindings (decorators) on its methods is effectively a controller. \n\nServices for private (in-container) use not exposing any event bindings can be alternatively implemented as class libraries (JavaScript/TypeScript modules), so directly imported and instantiated where used. It is a matter of preference. TyX was designed to favor named services with dependency injection versus direct import of modules. TypeScript support for interfaces and abstract classes can be utilized to decouple the service interface from its implementation(s). \n\n### 3.3. Events\n\nEvents trigger an execution of a Lambda function; TyX resolves the service and method bound to the event and together with the event data forms a Request object representing the event and pass it to method invocation. Using the provided decorators event data elements can be mapped to method arguments or even pass the complete Request object.\n\nServerless Framework provides a declarative approach (`serverless.yml`) to define event mappings per function. TyX support the standard HTTP events and follows the ApiGateway path syntax. In experimental stage are event bindings for S3, DynamoDB and Kinesis Stream events.  \n\n### 3.4. Container\n\nIn TyX the container has a twofold role both as a service registry and dependency injector and provides the entry point (handler) of the Lambda function. All services must be explicitly registered in the container either for internal use by `register` or `publish` their event bindings.\n\n```typescript\nexport const container = new LambdaContainer(\"example\")\n    // Use internal services\n    .register(PersistenceService)\n    .register(AuditService, { level: \"Detail\" })\n    // Publish public services\n    .publish(ReviewService);\n// Export the lambda handler function\nexport const handler: LambdaHandler = container.export();\n```\n\nRegistering services requires that class (constructor) is provided optionally together with arguments to be used to call the constructor. TyX only support property injection so services are preferred to provide default constructors. It is allowed to register specific instances (objects) as well. For a class to be considered a service it must have the `@Service` decorator and optionally implement the `Service` interface. \n\nThe container is implemented as a pool with record of the service registrations; while a container instance actually instantiate the services and resolve dependencies. So to process an event the container pool (e.g. `LambdaContainer`) will identify the event type, construct the Request object and prepare a container instance, then pass the processing to the instance. Instances are reused, once the event processing is finalized and the result is propagated back the instance is marked as ready to process the next incoming event. \n\nIn AWS Lambda execution environment the function instance is not reused until previous execution is complete and Node.js event loop is empty (by default), so the container pool will ever have a single instance in it. This requires that any resources that may keep the event loop busy are created before event processing and closed/released after its completion, e.g. database connections. For this purpose the `Service` interface defines two optional methods `activate` and `release`; all services implementing the methods are activated before and released after each event processing cycle.\n\nExpress does not have such limitation and the provided `ExpressContainer` can concurrently process multiple incoming requests. So the design of the container as pool/instance allows to accommodate both types of execution environment; and guarantee that each service instance is exposed to one event at a time.\n\n### 3.5. Proxy\n\nServices hosted in different Lambda functions can communicate via their public HTTP API, however this round-trip can be avoided as AWS Lambda provides for direct function invocation. TyX implements a RMI-like communication so uses synchronous Lambda invocation necessary so the returned result or the error thrown from the invoked service are made available to the invoking service as if the invoked service was a local instance. \n\nAWS Lambda bills both the \"waiting\" time of the invoking function as well as the \"running\" time of invoked function; so it may not be cost effective to host each service in its own function as default approach if services are tightly coupled. With the raising popularity of the serverless paradigm hopefully AWS will offer more optimal solutions for async lambda function invocation; this is particularly relevant for microservice based solutions on AWS Lambda. \n\nProxies are useful in case of integration between two applications when a subset of services are used by the other application or a dedicated service is created to provide the integration API. IAM policy can be used to further control the access beyond TyX token based authorization. TyX at moment requires that both applications (serverless projects) are deployed in the same AWS region.\n\n> Neither AWS Lambda or the Serverless Framework have the notion of application, project or solution. The closest concept is `API Gateway API` as collection of resources and methods that are integrated with back-end Lambda functions. So all functions deployed from a serverless project are exposed as an API instance with single stage assigned a common domain name. The deployed Lambda functions are not part of a group or collection that correspond to the API they implement. \n\n\n## 4. Data Structures\n\nService implementations and the supporting decorators are presented with two core data structure, the Request Object and the Context Object\n\n### 4.1. Request Object\n\nThe `HttpRequest` object is an based on HTTP event as received from API Gateway. The content type is additionally processed, if json is detected the body is parsed and made available as `json` property. Header names are converted to lowercase as convention choice.\n\n- Interface Definition\n```typescript\ninterface Request {\n    type: \"remote\" | \"internal\" | \"http\" | \"event\";\n    application: string;\n    service: string;\n    method: string;\n    requestId: string;\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\ninterface HttpRequest extends Request {\n    httpMethod: HttpMethod;\n    resource: string;\n    path: string;\n    sourceIp: string;\n\n    headers?: Record<string, string>;\n    pathParameters?: Record<string, string>;\n    queryStringParameters?: Record<string, string>;\n    body?: string | null;\n    isBase64Encoded?: boolean;\n\n    json?: any;\n    contentType?: HttpContentType;\n}\n\ninterface HttpHeader {\n    value: string;\n    params: Record<string, string>;\n}\n\ninterface HttpContentType extends HttpHeader {\n    domainModel?: string;\n    isJson?: boolean;\n    isMultipart?: boolean;\n}\n```\n\n- Example\n```json\n{\n    \"type\": \"http\",\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"sourceIp\": \"2.3.6.186\",\n    \"application\": \"tyx-sample5\",\n    \"service\": \"factory\",\n    \"method\": \"startProduction\",\n\n    \"httpMethod\": \"PUT\",\n    \"resource\": \"/product/{id}\",\n    \"path\": \"/product/red\",\n    \"pathParameters\": {\n        \"id\": \"red\"\n    },\n    \"queryStringParameters\": {\n        \"dummy\": \"param\"\n    },\n    \"headers\": {\n        \"authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n        \"cloudfront-forwarded-proto\": \"https\",\n        \"cloudfront-is-desktop-viewer\": \"true\",\n        \"cloudfront-is-mobile-viewer\": \"false\",\n        \"cloudfront-is-smarttv-viewer\": \"false\",\n        \"cloudfront-is-tablet-viewer\": \"false\",\n        \"cloudfront-viewer-country\": \"MK\",\n        \"content-type\": \"application/json; domain-model=startProduction\",\n        \"host\": \"2xuoozq2m7.execute-api.us-east-1.amazonaws.com\",\n        \"via\": \"1.1 edee3ff8f335740e0ea86cf9f62b5ae9.cloudfront.net (CloudFront)\",\n        \"x-amz-cf-id\": \"3s62OS3p-hVNJvXTTSF3MRNR2Y8aTz60s9HLtc-x0ZGwksJVGcRkwA==\",\n        \"x-amzn-trace-id\": \"Root=1-59f1cf28-1537e44a2e2b1d5917d05402\",\n        \"x-forwarded-for\": \"2.3.4.186, 54.182.239.90\",\n        \"x-forwarded-port\": \"443\",\n        \"x-forwarded-proto\": \"https\"\n    },\n    \"body\": \"{\\\"orderId\\\":\\\"start\\\"}\",\n    \"isBase64Encoded\": false,\n    \"contentType\": {\n        \"value\": \"application/json\",\n        \"params\": {\n            \"domain-model\": \"startProduction\"\n        },\n        \"domainModel\": \"startProduction\",\n        \"isJson\": true,\n        \"isMultipart\": false\n    },\n    \"json\": {\n        \"orderId\": \"start\"\n    }\n}\n```\n\n### 4.2. Context Object\n\nContext object contains the authorization token received, the invoked method permission definition and authorization info extracted from the token.\n\n- Interface Definition\n```typescript\ninterface Context {\n    requestId: string;\n    token: string;\n    permission: PermissionMetadata;\n    auth: AuthInfo;\n}\n\ninterface AuthInfo {\n    tokenId?: string;\n\n    issuer?: string;\n    audience?: string;\n    subject: \"event\" | \"remote\" | \"user:internal\" | \"user:external\" | \"user:public\" | string;\n    remote?: boolean;\n\n    userId: string;\n    role: string;\n    email?: string;\n    name?: string;\n    ipAddress?: string;\n\n    issued?: Date;\n    expires?: Date;\n}\n\ninterface PermissionMetadata {\n    service?: string;\n    method: string;\n    name: string;\n    roles: Roles;\n}\n\n```\n\n- Example, role restricted method\n```json\n{\n    \"requestId\": \"bbfb7cd5-ba45-11e7-bb80-356aa0e72897\",\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaWQiOiJtYW5hZ2VyIiwicm9sZSI6Ik1hbmFnZXIiLCJpYXQiOjE1MDkwMTk0MzIsImV4cCI6MTUwOTAyNjYzMiwiYXVkIjoidHl4LXNhbXBsZTUiLCJpc3MiOiJ0eXgtc2FtcGxlNSIsInN1YiI6InVzZXI6aW50ZXJuYWwiLCJqdGkiOiI5ZGJkYmMwYy0wMWRiLTRmN2ItYmY0ZS1kMmUzMmY1ZDExNWIifQ.pI_4JMgzXR4Ei9i0CH4lKsX59id-vNQqrIYzP8Yz8PI\",\n    \"permission\": {\n        \"service\": \"factory\",\n        \"method\": \"startProduction\",\n        \"name\": \"command\",\n        \"roles\": {\n            \"Admin\": true,\n            \"Manager\": true,\n            \"Operator\": false,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"tokenId\": \"9dbdbc0c-01db-4f7b-bf4e-d2e32f5d115b\",\n        \"subject\": \"user:internal\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": \"manager\",\n        \"role\": \"Manager\",\n        \"issued\": \"2017-10-26T12:03:52.000Z\",\n        \"expires\": \"2017-10-26T14:03:52.000Z\"\n    }\n}\n```\n\n- Example, public method\n```json\n{\n    \"requestId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n    \"permission\": {\n        \"service\": \"login\",\n        \"method\": \"login\",\n        \"name\": \"public\",\n        \"roles\": {\n            \"Public\": true,\n            \"Internal\": true,\n            \"Remote\": true\n        }\n    },\n    \"auth\": {\n        \"sessionId\": \"bbd02781-ba45-11e7-bdd5-7396a38f651f\",\n        \"subject\": \"user:public\",\n        \"issuer\": \"tyx-sample5\",\n        \"audience\": \"tyx-sample5\",\n        \"remote\": false,\n        \"userId\": null,\n        \"role\": \"Public\",\n        \"issued\": \"2017-10-26T12:03:52.464Z\",\n        \"expires\": \"2017-10-26T12:04:52.464Z\"\n    }\n}\n```\n\n## 5. Service Decorators\n\n### 5.1. `@Service` decorator\n\nThis decorator is used on classes, if the name is not specified the class name used as service name.\n\n```typescript\n@Service(name?: string)\n```\n\n### 5.2. `@Inject` decorator\n\nThis decorator is used on class properties that should be injected by the container. It is only valid in classes decorated with `@Service` or `@Proxy`. \n\nWhen `resource` is not provided the type name of property is used. The second argument `application` defaults to the application id specified when container is instantiated. When injecting a proxy it must match the value if provided in the `@Proxy` decorator.\n\n```typescript\n@Inject(resource?: string | Function, application?: string)\n```\n\n### 5.3. `@Proxy` decorator\n\nThis decorator is used on classes implementing service proxy. \n\nIt is mandatory to specify the `service` name. If `application` is not provided it defaults to application id specified when container is instantiated; it is necessary to provide this attribute if the service is part of a remote application. The `functionName` defaults to `(service)-function` but can be explicitly provided.\n\n```typescript\n@Proxy(service: string, application?: string, functionName?: string)\n```\n\n\n## 6. HTTP Decorators\n\nHTTP decorators are to be used over service methods, if the class is not decorated as `@Service` they have no effect.\n\n### 6.1. `@Get` decorator\n\nDecorate the service method to respond on HTTP GET on the specified route.\n\n```typescript\n@Get(route: string, adapter?: HttpAdapter)\n```\n\n### 6.2. `@Post` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route.\n\nIf `model` argument is not provided or `false` only one method can bind to the specified route. When `true` the incoming `Content-Type` must include parameter `domain-model=(methodName)` so allowing multiple methods to share the route. The `model` can be explicitly provided and have different value from decorated service method.\n\n```typescript\n@Post(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.3. `@Put` decorator\n\nDecorate the service method to respond on HTTP PUT on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Put(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.4. `@Delete` decorator\n\nDecorate the service method to respond on HTTP POST on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Delete(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.5. `@Patch` decorator\n\nDecorate the service method to respond on HTTP PATCH on the specified route. Argument `model` as in `@Post`.\n\n```typescript\n@Patch(route: string, model?: boolean | string, adapter?: HttpAdapter)\n```\n\n### 6.6. `@ContentType` decorator\n\nOverride the default content type `application/json` for the response.\n\n```typescript\n@ContentType(type: string)\n```\n\nSpecial type `HttpResponse` allows the method to provide a complete response corresponding to the following interface:\n\n```typescript\ninterface HttpResponse {\n    statusCode: HttpCode;\n    contentType?: string;\n    headers?: Record<string, string>;\n    body: any;\n}\n```\n\n### 6.7. `HttpAdapter` function\n\nIt is preferred to use [7. Method Argument Decorators] however a custom function can be provided to convert the context and request objects to method arguments. When a `HttpAdapter` is provided argument decorators are not evaluated.\n\n```typescript\ninterface HttpAdapter {\n    (\n        next: (...args: any[]) => Promise<any>,\n        ctx?: Context,\n        req?: HttpRequest,\n        path?: Record<string, string>,\n        query?: Record<string, string>\n    ): Promise<any>;\n}\n```\n- Example with argument decorators\n\n```typescript\n@Put(\"/product/{id}\", true)\npublic async startProduction(\n    @ContextParam(\"auth.userId\") userId: string,\n    @ContextParam(\"auth.role\") role: string,\n    @PathParam(\"id\") productId: string,\n    @Body() order: any): Promise<Confirmation> {\n}\n```\n\n- Equivalent with `HttpAdapter`\n\n```typescript\n@Put(\"/product/{id}\", true, (next, ctx, req, path) => next(\n    ctx.auth.userId,\n    ctx.auth.role,\n    path.id,\n    req.json\n))\npublic async startProduction(\n    userId: string,\n    role: string,\n    productId: string,\n    order: any): Promise<Confirmation> {\n}\n```\n\n## 7. Method Argument Decorators\n\n### 7.1. `@PathParam` decorator\n\nUse `@PathParam` decorator to inject path parameters in service methods:\n\n```typescript\n@Get(\"/notes/{id}\")\ngetOne(@PathParam(\"id\") id: string) { ... }\n```\n\n### 7.2. `@PathParams` decorator\n\nUse `@PathParams` decorator to inject record of all path parameters in service methods:\n\n```typescript\n@Get(\"/root/{p1}/{p2}/{p3}\")\naction(@PathParams() params: Record<string, string>) { ... }\n```\n\n### 7.4. `@QueryParam` decorator\n\nTo inject query parameters, use `@QueryParam` decorator:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParam(\"limit\") limit: number) { ... }\n```\n\n### 7.4. `@QueryParams` decorator\n\nUse `@QueryParams` decorator to inject record of all query parameters in service methods:\n\n```typescript\n@Get(\"/notes\")\ngetNotes(@QueryParams() query: Record<string, string>) { ... }\n```\n\n### 7.5. `@HeaderParam` decorator\n\nTo inject request header parameter, use `@HeaderParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@HeaderParam(\"host\") originHost: string, @Body() note: Note) { ... }\n```\n\n### 7.6. `@Body` decorator\n\nTo inject request body, use `@Body` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@Body() note: Note) { ... }\n```\n\nThe decorator does not support class transformation, interfaces can be used as arguments types.\n\n### 7.7. `@BodyParam` decorator\n\nTo inject request body parameter, use `@BodyParam` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@BodyParam(\"name\") noteName: string, @BodyParam(\"note.text\") text: string) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.8. `@ContextObject` decorator\n\nTo inject directly the Context object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextObject() context: Context, @Body() note: Note) { ... }\n```\n\n### 7.9. `@ContextParam` decorator\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@ContextParam(\"auth.userId\") userId: string, @Body() note: Note) { ... }\n```\n\nThe parameter may be given as dot separated path, it will evaluate to null or undefined if last token can not be reached.\n\n### 7.10. `@RequestObject` decorator\n\nTo inject directly the Request object, use `@ContextObject` decorator:\n\n```typescript\n@Post(\"/notes\")\nsaveNote(@RequstObject() req: HttpRequest) { ... }\n```\n\n## 8. Authorization Decorators\n\nAuthorization decorators allow access control at service method level. At most one of the decorators should be specified, when none is present the method is not available to process any events.  \n\n### 8.1. `@Public` decorator\n\nAllow public access to the service method via HTTP decorated routes.\n\n```typescript\n@Public()\n```\n\n### 8.2. `@Private` decorator\n\nService method is only allowed to be called within the container. HTTP decorators should not be used in combination.\n\n```typescript\n@Private()\n```\n\n### 8.3. `@Internal` decorator\n\nProxy calls allowed only from services from the same application. HTTP decorators should not be used in combination.\n\n```typescript\n@Internal()\n```\n\n### 8.4. `@Remote` decorator\n\nRemote proxy calls allowed from services of other applications. HTTP decorators should not be used in combination.\n\n```typescript\n@Remote()\n```\n\n### 8.5. `@Query` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods retrieving data, in combination with HTTP decorators.\n\n```typescript\n@Query<R extends Roles>(roles: R)\n```\n\n### 8.6. `@Command` decorator\n\nMethod allowed only to specified roles. This decorator should used on methods manipulating data or having other side effects, in combination with HTTP decorators.\n\n```typescript\n@Command<R extends Roles>(roles: R)\n```\n\n### 8.7. `@Invoke` decorator\n\nMethod allowed only to specified roles. Use this decorator in cases when the user action fulfilled by the service method is neither query or command.\n\n```typescript\n@Invoke<R extends Roles>(roles: R)\n```\n\nThe `Roles` interface defines the built-in reserved roles. When using `@Query`, `@Command` and `@Invoke` the reserved roles should not be explicitly specified, by default they are set as `Public: false`, `Internal: true`, `Remote: true`.\n\n```typescript\nexport interface Roles {\n    Public?: boolean;\n    Internal?: boolean;\n    Remote?: boolean;\n    Application?: never;\n    [role: string]: boolean;\n}\n```\n\n## 9. Interfaces and Classes\n\n### 9.1. Service\n\nServices can implement the provided interface to provide implementation of life-cycle handlers `activate` and `release` as well as the logger instance. Before a service method corresponding to the Lambda triggering event is executed all services registered in the container that provide implementation of `activate` are invoked to prepare for event processing. At this point the service can initialize any resources or connections. After completion of the event processing `release` is called so services can dispose or close any resources or connections that were initialized in `activate` or in business logic of the service methods (lazy initialization). The service public API and implementation must not provide methods or properties with these names for other purposes.\n\n```typescript\ninterface Service {\n    log?: Logger;\n    activate?(ctx?: Context): Promise<void>;\n    release?(ctx?: Context): Promise<void>;\n}\n```\n\n`BaseService` class is provided that initialize the logger in its constructor.\n\n### 9.2. Proxy\n\nThe is a `Proxy` interface that simply extends `Service` without additional behavior. Implementation of proxies is supported by two classes, `BaseProxy` and `LambdaProxy`.\n\n`BaseProxy` is intended as internal base class in the framework.\n\n```typescript\nabstract class BaseProxy implements Proxy {\n    public readonly log: Logger;\n    protected config: Configuration;\n    protected security: Security;\n    public initialize(config: Configuration, security: Security): void;\n    protected proxy(method: Function, params: IArguments): Promise<any>;\n    protected abstract token(req: RemoteRequest): Promise<string>;\n    protected abstract invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\n`LambdaProxy` is implementation over AWS SDK support for Lambda function invocation.\n\n```typescript\nabstract class LambdaProxy extends BaseProxy {\n    private lambda;\n    constructor();\n    protected token(req: RemoteRequest): Promise<string>;\n    protected invoke(req: RemoteRequest): Promise<any>;\n}\n```\n\nIt is used in all of the provided examples, with following pattern:\n\n```typescript\n@Proxy(ExampleApi)\nexport class ExampleProxy extends LambdaProxy implements ExampleApi {\n    public async serviceMethod(arg1: string, arg2: any): Promise<ReturnType> {\n        return this.proxy(this.serviceMethod, arguments);\n    }\n}\n```\n\n### 9.3. Containers\n\nContainers implement the following interface:\n\n```typescript\ninterface Container {\n    register(resource: Object, name?: string): this;\n    register(service: Service): this;\n    register(proxy: Proxy): this;\n    register(type: Function, ...args: any[]): this;\n    publish(service: Function, ...args: any[]): this;\n    publish(service: Service): this;\n\n    metadata(): ContainerMetadata;\n    state(): ContainerState;\n    prepare(): Container;\n\n    httpRequest(req: HttpRequest): Promise<HttpResponse>;\n    remoteRequest(req: RemoteRequest): Promise<any>;\n    eventRequest(req: EventRequest): Promise<EventResult>;\n}\n```\n\n`ContainerPool` is the base class for exposed container implementations `LambdaContainer` and `ExpressContainer`:\n\n```typescript\nclass ContainerPool implements Container {\n    // Only the additional members given\n\n    protected log: Logger;\n\n    constructor(application: string, name?: string);\n\n    public config(): Configuration;\n    public security(): Security;\n\n    public dispose(): void;\n}\n```\n\n`LambdaContainer` provides only an additional method to export the Lambda handler function:\n\n```typescript\nclass LambdaContainer extends ContainerPool {\n    constructor(applicationId: string);\n    public export(): LambdaHandler;\n}\n```\n\n`ExpressContainer` provides additional methods to `start` and `stop` the Express server; default port is 5000.\n\n```typescript\nclass ExpressContainer extends ContainerPool {\n    constructor(application: string, basePath?: string);\n    start(port?: number): Server;\n    stop(): void;\n}\n```\n\n### 9.4. Configuration\n\nThe `Configuration` interface and the provided `BaseConfiguration` represent the built-in configuration service.\n\n```typescript\ninterface Configuration {\n    appId: string;\n    stage: string;\n\n    logLevel: LogLevel;\n    resources: Record<string, string>;\n    aliases: Record<string, string>;\n\n    httpSecret: string;\n    httpTimeout: string;\n    internalSecret: string;\n    internalTimeout: string;\n    remoteTimeout: string;\n\n    remoteSecret(appId: string): string;\n    remoteStage(appId: string): string;\n}\n```\n\n```typescript\nabstract class BaseConfiguration implements Configuration {\n    protected config: Record<string, any>;\n\n    constructor(config?: Record<string, any>);\n    public init(appId: string): void;\n\n    public readonly appId: string;\n    public readonly stage: string;\n    \n    public readonly logLevel: LogLevel;\n    public readonly aliases: Record<string, string>;\n    public readonly resources: Record<string, string>;\n\n    public readonly httpSecret: string;\n    public readonly httpTimeout: string;\n    public readonly internalSecret: string;\n    public readonly internalTimeout: string;\n    public readonly remoteTimeout: string;\n\n    public remoteSecret(appId: string): string;\n    public remoteStage(appId: string): string;\n}\n```\n\n### 9.5. Security\n\nThe `Security` interface and the provided `BaseSecurity` implement the TyX token based authorization. \n\n```typescript\ninterface Security extends Service {\n    httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    issueToken(req: IssueRequest): string;\n}\n```\n\n```typescript\nabstract class BaseSecurity implements Security {\n    public readonly log: Logger;\n    protected abstract config: Configuration;\n\n    public httpAuth(req: HttpRequest, permission: PermissionMetadata): Promise<Context>;\n    public remoteAuth(req: RemoteRequest, permission: PermissionMetadata): Promise<Context>;\n    public eventAuth(req: EventRequest, permission: PermissionMetadata): Promise<Context>;\n    public issueToken(req: IssueRequest): string;\n\n    protected verify(requestId: string, token: string, permission: PermissionMetadata): Promise<Context>;\n    protected secret(subject: string, issuer: string, audience: string): string;\n    protected timeout(subject: string, issuer: string, audience: string): string;\n}\n```\n\n### 9.6. Logger\n\nThe `Logger` interface in TyX is currently implemented to emit to `console`, in the future it is to be extended to use provided log writers as registered service.\n\n`BaseService` creates a logger instance with `logName` being the service name and `emitter` the class name; these are part of the log lines emitted to console. When the service is implemented as multiple classes or scripts `emitter` is to identify where the log entries originate from.\n\n```typescript\nenum LogLevel {\n    ALL = 0,\n    TRACE = 0,\n    DEBUG = 1,\n    INFO = 2,\n    WARN = 3,\n    ERROR = 4,\n    FATAL = 5,\n    OFF = 6,\n}\nnamespace LogLevel {\n    function bellow(level: LogLevel): boolean;\n    function set(level: LogLevel): void;\n}\n\ninterface Logger {\n    todo(message: any, ...args: any[]): void;\n    fatal(message: any, ...args: any[]): any;\n    error(message: any, ...args: any[]): any;\n    info(message: any, ...args: any[]): void;\n    warn(message: any, ...args: any[]): void;\n    debug(message: any, ...args: any[]): void;\n    trace(message: any, ...args: any[]): void;\n    time(): [number, number];\n    timeEnd(start: [number, number], message: any, ...args: any[]): void;\n}\nnamespace Logger {\n    const sys: Logger;\n    function get(logName: string, emitter?: any): Logger;\n}\n```\n\n> TODO: Logger example\n\n### 9.7. Express Service\n\nSee example [2.6. Express service](#26-express-service).\n\n```typescript\nabstract class ExpressService extends BaseService {\n    protected process(ctx: Context, req: HttpRequest): Promise<HttpResponse>;\n    protected abstract setup(app: Express, ctx: Context, req: HttpRequest): void;\n    public release(): Promise<void>;\n}\n```","gitHead":"fcbb00a60f39fb82bdca4c1dfaffc21ea370d07b","homepage":"https://github.com/alitelabs/tyx#readme","_id":"tyx@0.3.66","_nodeVersion":"18.12.1","_npmVersion":"8.19.2","dist":{"integrity":"sha512-GzTCLb/U8Mlqwm1MYYSMuFaLRV1CSgMn4H9wPTPI3v11yrG7gna0kqzqDQjqOk7NBdJocbIC7vL9xL6woWAawQ==","shasum":"4eb2dfa11d7dfeff9739b73286275d7e43cb9e51","tarball":"https://registry.npmjs.org/tyx/-/tyx-0.3.66.tgz","fileCount":303,"unpackedSize":1053135,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICTcVinf8jBdoqkEMZ8NAzRZiiXaelCQkNXxugDBa2FNAiAF4zlaRJfqp5uM2linwLKnN8lKmOus7+tU8knGJ0KakA=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjpcSnACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoT3g//Q9EFgrD+YEsckQQbilTFuzFaC++n9YDiVC4aEUkpZCUv4aXy\r\nrPQXt2/gy3+ov4lMMGPyDY79tsW0tSoVkwF9M89VvjWei4SgSa8OQdZkbf6X\r\nXPpuNbghpEsvvve32WWWx8fLY3jsLWONz+hx6GXtEDt1tiMXcmkY0V0qxOBR\r\nAli8o5UzVDRdhKkHqCRxZQTCGd8vc2vkF0Mg4lwXzDRqFgbfBpE+bLH6VNoF\r\nQVYdimO982MI9ccXxzKiaH4AD9psz9cKYo+ZDu65n8/b8Bu5k9zQ0QQQWhlH\r\n6GKdZbEY8iM/3ZFaQ/BwJ50XjV8sh0HqN+Ur3MxHNQ0UNb8ZPDULqQoHMuG4\r\nW0S5TgUam39+YkYyadN3OJgY/xNmq0ZtuDi87iQCzocL6BO49xIrCpvHz+Sj\r\n79ZjLyF3B2r0phF7jlenK/0hLC58+LqFVKx+KvMhKRqMItOWBSgMYhex+8bR\r\nJJKbFOlwMJm32KY8hivtfOJXonpjlJAXR2OgIII1z54ALCpoq4zPWGJ5Pf7/\r\nk8sfhwcs69x5gBkMk9slbGU3u4jZX2vba5eEfJFocImKSkCJ60/padsqYVfY\r\n0gtfR0O5MiCsVAdQ4JKwyBpOebbHboyJrClvfOVg6uV2CtjnxqpHWtzY4Nse\r\nLcP4crXZF3h9C228TPUPvfYhCclEd5Atamw=\r\n=/Gd7\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"alitelabs","email":"labs@alite-international.com"},"directories":{},"maintainers":[{"name":"alitelabs","email":"labs@alite-international.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tyx_0.3.66_1671808167182_0.7603289684404422"},"_hasShrinkwrap":false}},"readme":"","maintainers":[{"name":"alitelabs","email":"labs@alite-international.com"}],"time":{"modified":"2022-12-23T15:09:27.592Z","created":"2017-07-17T12:39:39.998Z","0.0.0":"2017-07-17T12:39:39.998Z","0.0.1":"2017-09-12T13:50:19.059Z","0.1.0":"2017-11-01T09:49:42.659Z","0.1.1":"2017-11-01T10:17:08.167Z","0.1.2":"2017-11-03T08:51:52.734Z","0.1.3":"2017-11-06T10:27:54.758Z","0.1.4":"2017-11-23T12:50:58.507Z","0.1.5":"2018-04-18T11:32:25.269Z","0.1.6":"2018-04-19T13:03:47.980Z","0.1.7":"2018-04-19T21:03:06.671Z","0.1.8":"2018-04-24T20:45:37.073Z","0.1.9":"2018-04-24T21:26:29.358Z","0.1.10":"2018-05-07T22:59:05.651Z","0.1.11":"2018-05-07T23:22:56.524Z","0.1.12":"2018-05-07T23:42:19.683Z","0.1.13":"2018-05-08T07:28:19.941Z","0.1.14":"2018-05-08T11:28:45.909Z","0.1.15":"2018-05-09T00:37:19.121Z","0.1.16":"2018-05-10T19:01:54.598Z","0.1.17":"2018-05-10T19:13:33.886Z","0.1.18":"2018-05-10T19:22:05.287Z","0.1.19":"2018-05-11T00:04:34.450Z","0.1.20":"2018-05-12T11:27:47.158Z","0.1.21":"2018-05-12T12:17:54.400Z","0.1.22":"2018-05-12T13:44:03.553Z","0.1.23":"2018-05-12T14:05:53.785Z","0.1.24":"2018-05-12T14:42:44.020Z","0.1.25":"2018-05-12T16:57:35.079Z","0.1.26":"2018-05-12T17:25:56.571Z","0.1.27":"2018-05-12T17:51:45.601Z","0.1.28":"2018-05-15T19:38:47.579Z","0.1.29":"2018-05-16T02:07:38.209Z","0.1.30":"2018-05-16T15:48:05.247Z","0.1.31":"2018-05-20T15:56:33.262Z","0.1.32":"2018-05-21T23:25:42.524Z","0.1.33":"2018-05-24T07:52:47.480Z","0.1.34":"2018-05-31T20:47:44.462Z","0.1.35":"2018-05-31T20:59:06.433Z","0.1.36":"2018-05-31T22:23:54.373Z","0.1.37":"2018-06-06T05:31:18.534Z","0.1.38":"2018-06-10T09:46:48.140Z","0.1.39":"2018-06-10T10:22:15.439Z","0.1.40":"2018-06-10T10:24:53.022Z","0.1.41":"2018-06-10T12:15:45.636Z","0.1.42":"2018-06-11T04:09:02.013Z","0.1.43":"2018-06-17T11:40:26.189Z","0.1.44":"2018-06-18T00:55:06.362Z","0.1.45":"2018-06-19T01:34:00.263Z","0.1.46":"2018-06-20T01:58:06.649Z","0.1.49":"2018-07-04T11:22:29.913Z","0.1.50":"2018-07-04T12:43:07.303Z","0.1.51":"2018-07-04T13:36:39.835Z","0.1.52":"2018-07-04T14:38:00.909Z","0.1.53":"2018-07-04T17:55:51.142Z","0.1.54":"2018-07-05T00:45:51.068Z","0.1.55":"2018-07-05T03:27:14.177Z","0.1.56":"2018-07-05T04:02:51.009Z","0.1.57":"2018-07-05T10:49:34.921Z","0.1.59":"2018-07-10T09:08:34.366Z","0.1.61":"2018-07-10T09:13:31.215Z","0.1.62":"2018-07-12T12:08:19.696Z","0.1.64":"2018-10-21T20:21:04.153Z","0.1.65":"2018-10-26T10:52:17.956Z","0.1.66":"2018-11-16T08:59:56.239Z","0.1.67":"2018-11-17T19:42:31.091Z","0.1.68":"2018-11-17T20:57:31.085Z","0.1.70":"2019-01-03T08:35:13.987Z","0.1.71":"2019-01-29T07:47:35.814Z","0.1.72":"2019-03-07T07:52:13.388Z","0.1.73":"2019-03-07T08:02:54.507Z","0.1.74":"2019-03-07T08:34:22.230Z","0.1.75":"2019-03-11T17:44:21.850Z","0.1.76":"2019-03-11T18:06:29.272Z","0.1.77":"2019-03-11T18:44:06.372Z","0.1.78":"2019-03-11T19:42:57.882Z","0.1.79":"2019-03-11T23:27:23.430Z","0.1.80":"2019-03-13T00:25:03.564Z","0.1.81":"2019-03-14T03:15:12.885Z","0.1.82":"2019-03-14T04:05:15.644Z","0.1.83":"2019-03-14T04:43:02.152Z","0.1.84":"2019-03-14T12:49:45.416Z","0.1.85":"2019-03-14T14:44:55.484Z","0.1.86":"2019-03-16T08:24:23.838Z","0.1.87":"2019-03-17T18:42:11.603Z","0.1.88":"2019-03-24T09:19:13.204Z","0.1.89":"2019-04-03T06:08:59.245Z","0.1.90":"2019-04-06T22:24:59.731Z","0.1.92":"2019-04-06T23:39:51.166Z","0.1.93":"2019-04-06T23:44:34.237Z","0.1.94":"2019-04-06T23:58:05.848Z","0.1.95":"2019-04-07T00:32:22.733Z","0.1.96":"2019-04-07T14:35:37.930Z","0.1.97":"2019-04-07T20:08:31.654Z","0.1.98":"2019-04-09T00:29:29.896Z","0.1.99":"2019-04-09T00:50:53.066Z","0.1.100":"2019-04-09T09:22:58.119Z","0.1.101":"2019-04-09T09:27:13.187Z","0.1.102":"2019-04-09T12:45:15.729Z","0.1.103":"2019-04-10T02:39:10.461Z","0.1.104":"2019-04-10T08:49:56.081Z","0.1.105":"2019-04-10T11:18:13.456Z","0.1.106":"2019-04-10T13:42:48.293Z","0.1.107":"2019-04-11T06:33:53.186Z","0.1.108":"2019-04-11T10:47:39.028Z","0.1.109":"2019-04-11T11:56:07.244Z","0.1.110":"2019-04-12T05:52:23.014Z","0.1.111":"2019-04-12T07:27:40.161Z","0.1.112":"2019-04-12T11:44:28.823Z","0.1.113":"2019-04-12T15:16:48.270Z","0.1.114":"2019-04-12T21:19:36.135Z","0.1.115":"2019-04-12T22:55:27.478Z","0.1.116":"2019-04-13T08:42:15.816Z","0.1.117":"2019-04-14T12:26:53.985Z","0.1.118":"2019-04-14T17:35:50.382Z","0.1.119":"2019-04-15T12:27:27.230Z","0.1.120":"2019-04-16T11:39:10.550Z","0.1.121":"2019-04-16T14:08:03.257Z","0.1.122":"2019-04-17T09:50:10.468Z","0.1.123":"2019-04-17T11:14:31.166Z","0.1.124":"2019-04-17T15:16:13.477Z","0.1.125":"2019-04-18T14:21:16.039Z","0.1.126":"2019-04-18T23:01:47.354Z","0.1.127":"2019-04-19T01:11:44.530Z","0.1.128":"2019-04-19T01:33:45.039Z","0.1.129":"2019-04-19T02:33:17.185Z","0.1.130":"2019-05-01T11:19:56.298Z","0.1.131":"2019-05-02T20:24:24.986Z","0.1.132":"2019-05-06T13:19:12.595Z","0.1.133":"2019-05-28T08:06:34.375Z","0.1.134":"2019-05-28T09:52:12.294Z","0.1.136":"2019-05-28T09:57:11.281Z","0.1.137":"2019-07-10T08:13:39.419Z","0.1.138":"2019-09-26T12:53:37.105Z","0.1.139":"2019-12-05T09:44:46.671Z","0.1.140":"2019-12-05T11:24:31.620Z","0.1.141":"2019-12-05T11:48:40.908Z","0.1.142":"2019-12-05T20:21:10.246Z","0.2.1":"2019-12-06T09:09:33.558Z","0.2.2":"2020-05-21T08:38:24.169Z","0.2.3":"2020-05-21T11:47:28.015Z","0.2.4":"2020-11-04T12:04:12.979Z","0.2.5":"2022-04-13T10:04:17.249Z","0.2.8":"2022-06-03T08:36:25.846Z","0.2.9":"2022-09-05T07:41:35.785Z","0.3.0":"2022-10-06T12:07:03.736Z","0.3.1":"2022-10-06T12:26:56.175Z","0.3.1-dev1":"2022-10-06T15:37:53.607Z","0.3.3":"2022-10-06T16:08:15.843Z","0.3.4":"2022-10-06T16:45:12.133Z","0.3.5":"2022-10-10T08:11:01.914Z","0.3.6":"2022-10-14T09:49:17.518Z","0.3.61":"2022-10-28T08:19:08.908Z","0.3.62":"2022-12-14T11:51:00.870Z","0.3.63":"2022-12-14T21:29:17.716Z","0.3.64":"2022-12-15T09:56:53.102Z","0.3.65":"2022-12-15T11:35:56.605Z","0.3.66":"2022-12-23T15:09:27.485Z"},"readmeFilename":"","homepage":"https://github.com/alitelabs/tyx#readme","repository":{"type":"git","url":"git+https://github.com/alitelabs/tyx.git"},"author":{"name":"Alite Labs","email":"labs@alite-international.com"},"bugs":{"url":"https://github.com/alitelabs/tyx/issues"},"license":"MIT"}